<asterite>
By the way, anyone knows what the c ABI for returning a struct?
<asterite>
jhass: fixed :)
<asterite>
It was that, the issue, luckily
<asterite>
And a very interesting bug… do you want me to explain? It’s fun :-P
<jhass>
sure!
<jhass>
and congrats I guess :D
<asterite>
Congrats to you for triggering that bug
<jhass>
it just happened naturally :P
<asterite>
The thing is, when you do `def foo(&block)`, the return type of the block is marked as void because you don’t specify the return type (and if you call the block you will get void)
<asterite>
However, the associated function that is generated for the block does return something… kind of hard to explain why the compiler did that (it’s because the function was still being type inferred)
<asterite>
Now, the function returned a structure with more than a pointer size, but the code that invoked it didn’t expect that, it expected void
<asterite>
so I guess the part past the pointer size was overwriting the stack frame
<asterite>
Or something like that
<asterite>
and that’s why after that point any kind of random behaviour can happen
<asterite>
*with more than a register size… I think functions return things in registers, right?
<asterite>
Anyway, really interesting :)
<asterite>
By the way, while I reduced this issue I traversed your code and it looks really nice… I really hope we can have before(…), setup, etc., in specs :)
<jhass>
yeah, not sure if that'll work yet
<jhass>
I guess the instance var sharing would have to happen in the main object
<asterite>
The “Also why can't I pass a symbol?” in Signal.trap it’s because it would be (a bit) slower unnecessarily, because we’d have to do a big “case” to check the symbol and convert it to an integer
bcardiff has joined #crystal-lang
<asterite>
Some things in Ruby use symbols where an enum or just some constant would be ok… of course a symbol is more readable, but less performant if you have to convert it to another value
<jhass>
okay, but you don't trap in a loop or anything
<jhass>
it happens once at program boot
<asterite>
That’s true
<jhass>
and you could just build a constant hash
<asterite>
but if you write trap(:siggint)
<asterite>
you will get a runtime error
<asterite>
if you write Signal.trap(Signal::SIGGINT)
<asterite>
you will get a compile error
<asterite>
I think I prefer the later
<jhass>
mmh
<asterite>
It’s safter, it’s faster
<asterite>
The only disadvantage is a small readability penalt
<asterite>
y
<jhass>
I just hate verbosity I guess :P
<jhass>
anyway, it's nothing too important
<asterite>
Me too, but I hate slow code more :-P
<asterite>
and code that errors at runtime where it could error at compile time
<jhass>
finding a less verbose solution could be a long term goal, it's nothing important at this stage
bcardiff has joined #crystal-lang
<jhass>
there's one thing I wonder that I couldn't really find out yet: do macros have a namespace? Is there a difference between declaring them inside a class/module vs toplevel?
<asterite>
Yes, when you invoke a macro it’s kind of like regular method lookup
<asterite>
So for example the `property` macro is declared inside Object
<asterite>
if you try to use it at the top-level it won’t find it
<asterite>
Macros still need a lot of thought, though… like, you can’t invoke a macro like Object.property
<jhass>
okay, I figured as much. Any chance of transferring them with include/extend or their own mechanism?
<jhass>
also does that mean I can do SomeModule.macro ?
<asterite>
I think when you include a module that defines a macro, the macro will be available to the including class
<asterite>
But you can’t invoke a macro with a receiver… yet
<CraigBuchek>
asterite, waj: take a look at the Scala implementation of hashes. They're using something a little more sophisticated than red-black trees. I think they're using 2-3 trees.
<asterite>
When you iterate those hashes, are the keys sorted?
<asterite>
I mean, not sorted, but sorted according to the way they were inserted
<CraigBuchek>
Pretty sure. It's kind of a small optimization to red-black trees.
<asterite>
Cool
<CraigBuchek>
Anyway, be sure to check their implementation before committing to something. They've got a few advantages.
<CraigBuchek>
Oh, I'd guess they're sorted, not ordered.
<asterite>
It’s ok… we could also have many kinds of hashes optimized for different usages
<CraigBuchek>
I like his O(log32(n)) in the talk. Basically, log32(n) is 7 max, which is close to O(1).
<asterite>
and with the new custom array/hash syntax the transition from one hash to another should be painless
<CraigBuchek>
There's another version of the video, from Strange Loop (which I saw live).
<CraigBuchek>
Oh, I haven't seen the new syntax. Link?
<asterite>
It’s in the Changelog, but it’s not very documented, just small examples
<asterite>
Set {1, 2, 3}
<CraigBuchek>
They actually use the same or similar data structure for arrays, I think.
<CraigBuchek>
Nice.
<asterite>
So you could do LinkedList { 1, 2, 3 }
<asterite>
RedBlackTree {
<asterite>
etc.
<asterite>
with initial values
<CraigBuchek>
I've been considering how you can get a small number of collection delimiters — () [] {} to allow a larger number of collection types. Your new syntax is one of the better options.
<asterite>
Yes, we thought a lot about it, it was hard to avoid grammar conflicts
<asterite>
The good thing is that it almost makes sense, that syntax :-P
<asterite>
If {1, 2, 3} is a tuple, Set {1, 2, 3} would be like creating a Set out of a tuple
<asterite>
the other one is a hash, so it’s similar
<CraigBuchek>
The other good choice I came up with was something like [1, 2, 3].set, but it has the disadvantage that it looks like a method call on a Hash, but it's really done at compile time, not runtime. Not sure that's a big deal though.
<asterite>
Yes… the advantage of the new syntax is that you can use any type name there
<CraigBuchek>
So the video says that BitmappedVectorTrie is what they're using for arrays/list/vectors. That's the O(log32(n)) one for most operations.
<asterite>
But… for arays too?
<CraigBuchek>
Looks like I mis-remembered. They do use red-black trees for hashes. They're using 2-3 finger trees for dequeues.
<CraigBuchek>
The 2-3 finger trees are great for access to ends. The bitmapped vector tries are used for arrays, with decent access to the middle.
<jhass>
asterite: mmh, looks like I crashed the compiler again :P
<asterite>
Excellent :)
<asterite>
Cool. By the way, when I fix that the code won’t compile
<jhass>
yeah, thought so
<asterite>
instance variables can’t be accessed in `with … yield`
<asterite>
it’s not like ruby’s instance_eval
<jhass>
sadly :P
<asterite>
No, not at all
<asterite>
I had so many bugs with instance_eval
<asterite>
When you use instance eval and want to access an instance variable of the object invoking the method with the block, then it’s very confusing
<jhass>
mmh, it's okay for me once you learn that there's not just self but also the definee
<asterite>
This: foo { puts @hello }
<asterite>
Now, if foo captures the block and uses instance_eval on some other object, the @hello var belongs to that object, not the one where you are standing
<jhass>
yeah, I guess not allowing instance variable access can make sense from a language design point of view
<asterite>
Yes, specially because the hash would mix the types
<asterite>
But also, the block is captured and then evaluated on another object, right?
<jhass>
no, currently the context of the callbacks and examples is not changed
<jhass>
the describe block context is changed however
<jhass>
so they should inherit that one
<asterite>
But how is “before” implemented?
<jhass>
currently just stores the block and calls it
<jhass>
it's more a stub until I figure out how to make it work nicely
<jhass>
but I just realized that I don't need global methods already \o/
<jhass>
beyond describe
<asterite>
Cool :)
<asterite>
How about not using instance vars in before? I like let(…)
<asterite>
I don’t think I like the way state is shared with instance vars in specs
<asterite>
for me it make the specs really hard to follow when they become big
<jhass>
yeah, let is nice
<jhass>
I guess we would need to make it a macro that defines methods on some module that's included into the Context though
<jhass>
and I'd still want to keep before to run some code before each/all example of that context
<asterite>
But still, if you assign instance vars in a “before” then they would be considered nilable by the compiler, I thin
<asterite>
k
<jhass>
we would need to find a way to make clear that assigning instance vars there is a noop I guess
<jhass>
actually I wonder why it doesn't error out already
<jhass>
since it's a captured block
<asterite>
A captured block can refere to instance vars… it closures “self"
<asterite>
The problem is that the bug you found is that instance vars refer to “self” but with the type of the yielded object
<asterite>
Really ugly :(
<asterite>
and I’m not sure how to fix it, it’s like we would need to have two scopes, one for the current type and one for the yielded type
<asterite>
which makes me wonder again if `with … yield` is really a good idea, despite making code less verbose
<asterite>
(because maybe with macros we can achieve the same thing, maybe we can generate the resulting code at compile time)
<jhass>
I'm not sure, I get the feeling that we would quickly end up overusing macros
<jhass>
I think there's too huge potential to write opaque code if we do everything with them
<jhass>
since they do not share a runtime environment with the rest of your code, you end up with two programs mixed together
<jhass>
one executed at compile time that generates (>) 50% of your runtime code
<jhass>
and then you might get to confused as to what you can access where
<jhass>
is that variable now a compile time variable or a runtime variable? etc
<asterite>
It’s true, I also wouldn’t like to abuse macros
<asterite>
Well, I guess we need to rethink `with … yield` then (yield with scope)
<jhass>
they're great to take out redundancy and to beautify parts of the code, like my raise_error macro that hides creating a new instance of a class
<jhass>
but the border to them being actual programs them self gets blurry already
<jhass>
Like I wrote a macro that can implement a basic Enumerator for to_enum like functionality
<asterite>
But that returns an array out of a method that yields, right?
<jhass>
the pattern in ruby is def foo; return to_enum(:foo) unless block_given?; yield; end
<jhass>
that returns an instance if Enumerator if no block is given
<asterite>
But we don’t have Enumerator
<jhass>
Enumerator just includes Enumerable and implements an each that calls the original method
<asterite>
I think Ruby’s enumerator uses fibers
<jhass>
Which allows you to do stuff like array.each_with_object(foo).map {|item, object| ...
<asterite>
Lunch time… I’d like to see that to_enum macro :)
<asterite>
jhass: another thing, if you do class Foo::Bar::Baz and Foo and Foo::Bar don’t exist the compiler will declare them as modules, you don’t need to pre-declare them like in Ruby
<jhass>
mmmh, not sure that's a wise idea tbh.
<jhass>
for example if for some reason the load order of things changes, especially if you encourage stuff like require "./*" and you want to make Bar a class later it'll break
<asterite>
jhass: we just release 0.5.1 in case you want to update the aur package. We’ll change the CRYSTAL_PATH and wrapper issue in a future release, we realized it’s a bit messy :)
<asterite>
Yes, they stopped working at some point (or never worked), but since no one is complaining… :-P
<jhass>
I recently got a user in #ruby interested but he was on vacation and only had 32bit machine available :P
<asterite>
we’ll take a look at it, or you can try cross compiling to a virtual machine and see if it works… I don’t remember what was the issue exactly
<asterite>
but it shouldn’t be that hard to solve
<jhass>
I tried to get that omnibus stuff running on 32bit already but didn't get too far tbh.
<asterite>
There are some manual steps that need to be done and are not documented :(
<asterite>
but you can submit issues to that project and we can make it better
<asterite>
or was it that you couldn’t make omnibus run at all?
<jhass>
nah, I got a vm too boot, the install didn't work but I could omnibus to run inside the vm
<jhass>
I also managed to let it built a 32 bit llvm I think
<jhass>
but then it wouldn't use that for building crystal or something, I forgot the details already tbh.
<asterite>
waj is the one maintaining that omnibus stuff, so I don’t know the exact details either