From: dblack@... Date: 2007-08-17T07:28:58+09:00 Subject: Re: Lazy function definition pattern in Ruby? --1926193751-1334731984-1187303337=:28099 Content-Type: MULTIPART/MIXED; BOUNDARY="1926193751-1334731984-1187303337=:28099" This message is in MIME format. The first part should be readable text, while the remaining parts are likely unreadable without MIME-aware tools. --1926193751-1334731984-1187303337=:28099 Content-Type: TEXT/PLAIN; charset=X-UNKNOWN; format=flowed Content-Transfer-Encoding: QUOTED-PRINTABLE Hi -- On Fri, 17 Aug 2007, Wolfgang N=C3=A1dasi-Donner wrote: > Sam Kong wrote: >> Hi, >> >> Yesterday, I read a blog about lazy function definition pattern in >> JavaScript at http://peter.michaux.ca/article/3556 . >> It was interesting and insightful. >> >> >> Write a function foo that returns a Date object that holds the time >> that foo was first called. >> >> var foo =3D function() { >> var t =3D new Date(); >> foo =3D function() { >> return t; >> }; >> return foo(); >> }; >> >> >> In ruby, one would write the following way or something like that if >> he wants to cache the first value. >> >> def foo >> @t or (@t =3D Time.new) >> end >> >> But the writer wants to remove the conditional part because it's run >> every time the function is called. >> JavaScript allows functions to be redefined very easily. >> I think ruby allows it but not very easily. >> >> I came up with this idea. >> >> class Lazy >> def method_missing *args >> if args[0] =3D=3D :foo >> @t =3D Time.new >> class << self >> def foo >> @t >> end >> end >> return foo >> end >> end >> end >> >> But I believe that ruby gurus will have better ideas. >> What would be the lazy function definition pattern in ruby? >> And do you think it's useful? >> >> Thanks in advance. >> >> Sam > > You can define a method inside a method directly. > > class Bar > def foo > @t =3D Time.new > def foo > @t > end > @t > end > end > > x=3DBar.new > p x.foo # =3D> Thu Aug 16 22:17:17 +0200 2007 > sleep 5 > p x.foo # =3D> Thu Aug 16 22:17:17 +0200 2007 A possible problem with that code is that it only works for one instance of Bar: Bar.new.foo # Thu Aug 16 18:23:02 -0400 2007 Bar.new.foo # nil My code is per-object: Bar.new.foo # Thu Aug 16 18:25:02 -0400 2007 Bar.new.foo # Thu Aug 16 18:25:03 -0400 2007 and each object keeps its own. Another possibility is: class Bar def foo t =3D Time.now self.class.class_eval do define_method(:foo) { t } end t end end That would preserve the time from the very first call to the method, across all instances. It depends how one wants to fine-tune the behavior, I guess. David --=20 * Books: RAILS ROUTING (new! http://www.awprofessional.com/title/0321509242) RUBY FOR RAILS (http://www.manning.com/black) * Ruby/Rails training & consulting: Ruby Power and Light, LLC (http://www.rubypal.com) --1926193751-1334731984-1187303337=:28099-- --1926193751-1334731984-1187303337=:28099--