Passing a block to a method for it to use for sorting

Crystal is great, and I’m getting stuff done faster than in almost any other language. But I am stuck on this, where in the main code I write a pass a block to a method in some class for it to use for sorting. The documentation is unclear and while I keep finding all sorts of fine examples of Crystal code, I’m not seeing the correct way to do this. Stripped down to bare essentials, my code is like this:

class Stuff
    @x, @y    # some sortable type
end

class Something
    @stuff : Array(Stuff)      # thousands of Stuff, and Stuff is a complicated thing
    def fancywork(sorter)
        stuff.sort sorter
    end
end

In the main code:

something.fancywork(  { |a,b|  [a.x <=> b.x, a.y <=> b.y } )

Later on I’ll want to feed it a different comparison block, for example

something.fancywork(  { |a,b|  [b.y <=> a.y, a.x <=> -b.x } )

But I am sure I’ve got the syntax wrong. The Crystal compiler keeps telling me “unterminated call” in the main code at those lines.

The block must go outside () and you’re not closing the array literal that you opened with [ inside the block.

Yeah, the first error is mismatched braces. You need to replace [ with { or } with ] to get a tuple literal or array literal, respectively. The former is probably better because it doesn’t allocate on the heap.

Then you need to specify if you want the sorter to be an inlined block or a (captured) proc. There’s a chapter Blocks and Procs in the language reference explaining these concepts and the differences. See also my recent post in Block forwarding and signature inference

Ah, a stupid typo! [ … } I’m sure that wasn’t in the original source code. But I will check…

Original source had proper [ ] or { }, but my bad, I wrote sloppy example code. I had the block inside the ( ) of the method call. Okay, now it’s outside, I’ve read that info recommended by straight-shoota, and now I have this code (copy-pasted to avoid error):

def fancywork(dems : Demands,  name : String,  &block)
    sorted = Demands.new(name)
    sorted.fams = fams.sort { |a,b|  yield a,b }
    return sorted
end