This idiom is pretty common:
class Foo
def time
@time ||= Time.now
end
end
class Foo
def time
@time ||= Time.now
end
end
foo = Foo.new
p foo.time # => 2016-07-20 17:31:19 -0300
sleep 1
p foo.time # => 2016-07-20 17:31:19 -0300
It would be nice if the standard library provided a macro for this. Just very few strokes would be saved, but it's probably more clear and idiomatic this way.
Implementing this is very easy. For example:
class Object
macro lazy_getter(name)
def {{name.target.id}}
@{{name.target.id}} ||= {{name.value}}
end
end
end
class Foo
lazy_getter time = Time.now
end
But maybe it doesn't look very nice. Some thoughts for an API:
lazy_getter time = Time.now
getter lazy: time = Time.now
lazy getter: time = Time.now
These last two can be implemented as an overload with required named arguments. I personally like the second form, but I wouldn't mind the first one.
Thoughts?
What about letting getter
take block?
getter time : Time { Time.now }
That can allow for the more complex, multline cases where you would normally do @foo ||= begin; ... end
Looks good at first, but what if I don't need to specify the type? Just Time.now
is enough here to guess the type from that. But this doesn't work:
getter time { Time.now }
because the block is bound to time
. But we could use a symbol and problem solved, though it's not consistent to other forms of getter that allow just a name. That is, this works:
getter :time { Time.now }
(I don't mind having to use a symbol, specially because the lazy form is less common than other forms)
Also both, getter(time) { Time.now }
and getter time do Time.now end
will work too.
Most helpful comment
Also both,
getter(time) { Time.now }
andgetter time do Time.now end
will work too.