Part II — Blocks & control flow

Blocks are Quoin's closures, and they're also how all control flow works — there are no if/while statements, only messages sent to booleans and blocks.

Nav: Foundations · Blocks & control · Objects · Patterns & errors · Concurrency & iteration · Networking & the web · Types · Tooling · Library & reference · Appendices


7. Blocks & closures

Rules

var double = { |n| n * 2 }
double.value:21                  "* -> 42
var adder = { |a b| a + b }
adder.valueWithArgs:#(3 4)       "* -> 7
{ |a b| a + b }.arity            "* -> 2
{ #greet |x| 'hi ' + x }.name    "* -> #greet

Closures capture the live environment, so a block can see — and call — names that change after it was created (this is how recursive named blocks work):

var count = 0
var bump = { count = count + 1 }
bump.value
bump.value
count                            "* -> 2

Other invocation selectors exist for binding a receiver as well as arguments — valueWithSelf:, value:withSelf:, valueWithSelfOrArg: — these are mostly used by the iteration protocol (Part V) to pass each element as both self and the block argument.


8. Control flow is a library, not syntax

Rules

var score = 95
(score > 90).if:{ 'A'.print } else:{ 'not yet'.print }

var x = nil
(x == nil).if:{ 'missing'.print }     "* compare to produce a boolean first

var i = 1
{ i <= 3 }.whileDo:{ i.print; i = i + 1 }

Because conditionals are just messages, the receiver of .if: must already be a boolean. Comparison operators (==, <, …) and predicate methods (defined?, contains?:, …) are how you produce one.

⚠ Gotcha — nil.if: is an error, not "false". Many languages treat nil as falsy; Quoin does not. maybe.if:{ … } throws MessageNotUnderstood when maybe is nil (or any non-boolean). Guard with an explicit test: maybe.defined?.if:{ … } or (maybe == x).if:{ … }.


9. Returns & non-local return

Rules

Finder <- {
    firstBig: -> { |list|
        list.each:{ |n|
            (n > 100).if:{ ^^ n }  "* ^^ returns from firstBig:, ending the loop
        };
        nil                        "* fell through: nothing big
    }
}

Finder.new.firstBig:#(7 200 9)     "* -> 200

Inside the each: block, ^ n would merely end that one iteration of the block (returning n as the block's value, which each: discards) — the loop would continue. ^^ n is what actually exits firstBig:. The standard whileDo: is itself defined using ^^ to unwind its recursion.


Next: Part III — Objects.