Lazy function definition pattern in Ruby?

S

Sam Kong

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
 
D

dblack

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

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

Wolfgang Nádasi-Donner

Sam said:
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
 
C

Chris Carter

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
 
S

Sam Kong

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

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
 
S

Sam Kong

Sam said:
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.

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

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.
 
D

dblack

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

Sam said:
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 =3D function() {
var t =3D new Date();
foo =3D 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 =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--
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top