Lazy function definition pattern in Ruby?

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.

<snip>
Write a function foo that returns a Date object that holds the time
that foo was first called.

var foo = function() {
    var t = new Date();
    foo = function() {
        return t;
    };
    return foo();
};
</snip>

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 = 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] == :foo
      @t = 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

Hi --

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.

<snip>
Write a function foo that returns a Date object that holds the time
that foo was first called.

var foo = function() {
   var t = new Date();
   foo = function() {
       return t;
   };
   return foo();
};
</snip>

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 = 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] == :foo
     @t = 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.

You could do this (and I think it's similar to the "once" technique
[pattern?] that's used in the Date library and talked about in the
Pickaxe):

   def my_time
     t = Time.now
     (class << self; self; end).class_eval do
       define_method(:my_time) { t }
     end
     t
   end

David

···

On Fri, 17 Aug 2007, Sam Kong wrote:

--
* 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)

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.

<snip>
Write a function foo that returns a Date object that holds the time
that foo was first called.

var foo = function() {
    var t = new Date();
    foo = function() {
        return t;
    };
    return foo();
};
</snip>

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 = 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] == :foo
      @t = 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 = Time.new
    def foo
      @t
    end
    @t
  end
end

x=Bar.new
p x.foo # => Thu Aug 16 22:17:17 +0200 2007
sleep 5
p x.foo # => Thu Aug 16 22:17:17 +0200 2007

Wolfgang Nádasi-Donner

···

--
Posted via http://www.ruby-forum.com/\.

Why not just use a closure, and do it the way you would in JS?

foo = proc { x=Time.now; foo = proc { x } }; foo.call

Then you just access it with foo/foo.call

···

On 8/16/07, dblack@rubypal.com <dblack@rubypal.com> wrote:

You could do this (and I think it's similar to the "once" technique
[pattern?] that's used in the Date library and talked about in the
Pickaxe):

   def my_time
     t = Time.now
     (class << self; self; end).class_eval do
       define_method(:my_time) { t }
     end
     t
   end

--
Chris Carter
concentrationstudios.com
brynmawrcs.com

I didn't know defining the same method in a method works.
It's very similar to the one David suggested above.
But the syntax is easier and more intuitive.
It's almost same as JavaScript's pattern.
It's good to know.^^

Thanks.

···

On Aug 16, 1:18 pm, "Wolfgang Nádasi-Donner" <ed.oda...@wonado.de> wrote:

Sam Kong wrote:
> Hi,

> Yesterday, I read a blog about lazy function definition pattern in
> JavaScript athttp://peter.michaux.ca/article/3556.
> It was interesting and insightful.

> <snip>
> Write a function foo that returns a Date object that holds the time
> that foo was first called.

> var foo = function() {
> var t = new Date();
> foo = function() {
> return t;
> };
> return foo();
> };
> </snip>

> 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 = 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] == :foo
> @t = 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 = Time.new
    def foo
      @t
    end
    @t
  end
end

x=Bar.new
p x.foo # => Thu Aug 16 22:17:17 +0200 2007
sleep 5
p x.foo # => Thu Aug 16 22:17:17 +0200 2007

Wolfgang Nádasi-Donner
--
Posted viahttp://www.ruby-forum.com/.

Hi --

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.

<snip>
Write a function foo that returns a Date object that holds the time
that foo was first called.

var foo = function() {
    var t = new Date();
    foo = function() {
        return t;
    };
    return foo();
};
</snip>

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 = 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] == :foo
      @t = 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 = Time.new
   def foo
     @t
   end
   @t
end
end

x=Bar.new
p x.foo # => Thu Aug 16 22:17:17 +0200 2007
sleep 5
p x.foo # => 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 = 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

···

On Fri, 17 Aug 2007, Wolfgang Nádasi-Donner wrote:

--
* 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)

I also thought of it.
But foo.call isn't so good.
I think JavaScript's syntax is better than ruby's about returning a
function.

Sam

···

On Aug 16, 1:20 pm, "Chris Carter" <cdcar...@gmail.com> wrote:

On 8/16/07, dbl...@rubypal.com <dbl...@rubypal.com> wrote:

> You could do this (and I think it's similar to the "once" technique
> [pattern?] that's used in the Date library and talked about in the
> Pickaxe):

> def my_time
> t = Time.now
> (class << self; self; end).class_eval do
> define_method(:my_time) { t }
> end
> t
> end

Why not just use a closure, and do it the way you would in JS?

foo = proc { x=Time.now; foo = proc { x } }; foo.call

Then you just access it with foo/foo.call

--
Chris Carter
concentrationstudios.com
brynmawrcs.com

That's easily fixable, just s/@/@@/

···

On 8/16/07, dblack@rubypal.com <dblack@rubypal.com> wrote:

A possible problem with that code is that it only works for one
instance of Bar:

Hi --

···

On Fri, 17 Aug 2007, Logan Capaldo wrote:

On 8/16/07, dblack@rubypal.com <dblack@rubypal.com> wrote:

A possible problem with that code is that it only works for one
instance of Bar:

That's easily fixable, just s/@/@@/

As long as you don't want to do the same thing in a subclass....

David

--
* 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)

Everything is a tradeoff.

···

On 8/16/07, dblack@rubypal.com <dblack@rubypal.com> wrote:

Hi --

On Fri, 17 Aug 2007, Logan Capaldo wrote:

> On 8/16/07, dblack@rubypal.com <dblack@rubypal.com> wrote:
>> A possible problem with that code is that it only works for one
>> instance of Bar:
>
> That's easily fixable, just s/@/@@/

As long as you don't want to do the same thing in a subclass....

Hi --

···

On Fri, 17 Aug 2007, Logan Capaldo wrote:

On 8/16/07, dblack@rubypal.com <dblack@rubypal.com> wrote:

Hi --

On Fri, 17 Aug 2007, Logan Capaldo wrote:

On 8/16/07, dblack@rubypal.com <dblack@rubypal.com> wrote:

A possible problem with that code is that it only works for one
instance of Bar:

That's easily fixable, just s/@/@@/

As long as you don't want to do the same thing in a subclass....

Everything is a tradeoff.

I'm not sure what the disadvantage of the local variable is, though.
It seems like a good fit, since all you need it for is the local
purpose of preserving it in the new definition.

David

--
* 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)