Crystal: Curly Braces and 'do...end' Blocks Behaving Differently for Proc getter

Created on 31 Jan 2020  路  6Comments  路  Source: crystal-lang/crystal

As far as I'm aware, using braces or 'do..end' to delimit a block should be identical. However, in this example, the latter won't even compile.

class Example
  getter foo = Proc(Nil).new { }
end

Compiles and runs, while

class Example
  getter foo = Proc(Nil).new do end
end

crashes and burns:

There was a problem expanding macro 'getter'

Code in bug.cr:2:2

 2 | getter foo = Proc(Nil).new do end
     ^
Called macro defined in macro 'macro_140517701601472'

 117 | macro getter(*names, &block)

Which expanded to:

 > 5 | 
 > 6 |         
 > 7 |           def foo = Proc(Nil).new
                         ^
Error: unexpected token: =

This problem also occurs with the class_getter macro.

Here are my system details:

$ uname -r
4.14.167-1-MANJARO

$ crystal -v
Crystal 0.32.1 (2019-12-18)

LLVM: 9.0.0
Default target: x86_64-pc-linux-gnu
question

Most helpful comment

I think this is treated as

 getter(foo = Proc(Nil).new) do end 

which is expected behavior according to operator precedence. do and braces certainly do not have the same precedence.

All 6 comments

You're missing ; in between do and end.

@Sija The error still occurs even with the addition of a semicolon. A newline also doesn't fix the issue (I had initially encountered it with a block actually present, rather than just do end).

Adding ; won't help. This one outside getter works:

foo = Proc(String).new do "foo" end

In a way it's similar to #8715 where private and record works separately but not together.

I think this is treated as

 getter(foo = Proc(Nil).new) do end 

which is expected behavior according to operator precedence. do and braces certainly do not have the same precedence.

https://crystal-lang.org/api/0.32.1/Object.html#getter(*names,&block)-macro

If a block is given to the macro, a getter is generated with a variable that is lazily initialized with the block's contents:

class Person
  getter(birth_date) { Time.local }
end

https://crystal-lang.org/reference/syntax_and_semantics/blocks_and_procs.html

The difference between using do ... end and { ... } is that do ... end binds to the left-most call, while { ... } binds to the right-most call.

Duplicate of #7286

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Sija picture Sija  路  3Comments

cjgajard picture cjgajard  路  3Comments

RX14 picture RX14  路  3Comments

lbguilherme picture lbguilherme  路  3Comments

costajob picture costajob  路  3Comments