Implement Swift's Lazy Variable Syntax for Crystal
There are many situations where we have a property for an object that is expensive to compute. When that property is not used often, it makes sense to
- defer the computation until the first time we need the property, and
- store the value for subsequent references to avoid re-computing it.
Ruby and Crystal developers are familiar with this as “memoization” where the property is access by a method that computes and caches the value.
|  |  | 
Swift has a language feature for memoization using the lazy keyword to declate dynamic properties for an object.
|  |  | 
This looks so intuitive that I wanted to figure out if I could implement this for my Crystal1 programs. Since Crystal is really good at not compiling unneeded code, and has great macro support2, I started to look into how I could make a lazy keyword available in Crystal.
The sugar
|  |  | 
The macro
The following lazy macro converts the lazy prop : T { ... } declaration into the boilerplate for memoization by generating
- a private member/property @prop : T?,
- a memoizing getter method prop, and
- a private method _lazy_prop_fetchwith the evaluation code.
|  |  | 
Error handling
Crystal’s type inference only goes so far. Declaring lazy sin { Math.sin(@value) } will not compile, so the lazy macro catches that otherwise very natural usage to provide a useful error.
For example, the following declaration of twice …
|  |  | 
… will result in the following compile-time error:
|  |  | 
Availability
I’ve started a sugar.cr shard in GitHub. This macro is too small to be in its own shard; but I can foresee other similar sugar crystals 😉 that I think will just go into this repo.
- 
Crystal is a compiled statically-typed language with Ruby-inspired syntax. ↩︎ 
- 
Macros in Crystal are great, and the documentation here provides plenty of information to really understand and use them. ↩︎ 
