Trying to be just ducky…
class X
def to_proc
self
end
def call
“x”
end
end
x = X.new
def y( &b )
b.call
end
y(&x)
TypeError: X#to_proc should return Proc
from (irb):14
Why isn’t it enough that it x responds to #call?
T.
Trying to be just ducky…
class X
def to_proc
self
end
def call
“x”
end
end
x = X.new
def y( &b )
b.call
end
y(&x)
TypeError: X#to_proc should return Proc
from (irb):14
Why isn’t it enough that it x responds to #call?
T.
[email protected] wrote:
Why isn’t it enough that it x responds to #call?
Personally, I don’t mind that objects given as blocks must define a
#to_proc method; what I don’t like is that the return value must be a
Proc. It should just check if the return value defined a #call method.
The reason I think the #to_proc method should be there is that the
semantics of #call heavily depends on the context in which it’s in:
class PhoneNumber
def call; end
end
#to_proc is by convention only defined on objects that in some way think
of themselves as procs – #call can be defined on a lot of objects, for
a variety of reasons.
That may not be completely “ducky”, but I think it’s common sense.
Daniel
Right. It’s not the #to_proc I’m worried about. I completely agree with
your assessment and that is exactly what I’m thinking too.
T.
[email protected] wrote:
Right. It’s not the #to_proc I’m worried about. I completely agree with
your assessment and that is exactly what I’m thinking too.
Good to know
If some of you want a use case, take this (wrote it a few weeks ago):
class CachedProc
def initialize(&proc)
@proc = proc
@cache = Hash.new{|cache, args| cache[args] = @proc.call(*args)}
end
def call(*args)
@cache[args]
end
alias_method :[], :call
def to_proc
# must return a Proc...
@proc
end
def method_missing(name, *args, &block)
@proc.send(name, *args, &block)
end
end
def cached_proc(&proc)
CachedProc.new(&proc)
end
This is fine and all, but doesn’t work with iterators and such:
proc = cached_proc{|obj| expensive_operation(obj)}
[2, 5, 7, 4, 2, 8, 2].collect(&proc)
Here, the caching doesn’t work, because the CachedProc is converted to a
Proc.
Daniel
Daniel S. wrote:
alias_method :[], :call
Here, the caching doesn’t work, because the CachedProc is converted to a
Proc.
def to_proc
proc {|*args| self.call(*args) }
end
Cheers,
Dave
def to_proc
proc {|*args| self.call(*args) }
end
Yea, and I ended up with
def to_proc
proc { |dummy| self }
end
But obviously the restriction is forcing some ugly code on us here.
T.
Dave B. wrote:
def to_proc
proc {|*args| self.call(*args) }
end
Yes, that works (thanks!), but I think it’s against Ruby spirit to
require a certain class for a relatively high-level thing like this. I
can see why there’s not really any way around a string ultimately being
a String object, through #to_str or #to_s, but all that’s really
required by the return value of #to_proc is an object that responds to
#call.
Daniel
2006/5/21, Ross B. [email protected]:
I guess it’s probably the way it is because call isn’t involved when a
method uses yield…?
That would be my guess also. Trans, please note that there is an
additional, implicit conversion step if you hand a block to a method
and use it via &b. Also, a proc handed over via &b still can be
invoked via yield so there are some (optimized) things going on behind
the scenes.
Regards
robert
On Sun, 2006-05-21 at 18:22 +0900, Daniel S. wrote:
#call.
I guess it’s probably the way it is because call isn’t involved when a
method uses yield…?
l = lambda { |a| p a }
def l.call(*args); nil; end
l.call(1)
[1,2].each(&l)
1
2
Dave B. wrote:
#call.
You can actually use certain non-Proc objects:
irb> def say_hello_to() yield “hello” end
=> nil
irb> say_hello_to &method(:puts)
hello
But is that because of #to_proc the the method object, or is Ruby
treating method objects different?
Getting off-topic, if I may revisit your cached_proc again – you can
easily do without the class entirely.def cached_proc &block
cache = Hash.new {|h, k| h[k] = block.call(*args) }
proc {|*args| cache[args] }
end
Yeah, that simplifies things quite a bit, thanks mate!
Daniel
Daniel S. wrote:
#call.
You can actually use certain non-Proc objects:
irb> def say_hello_to() yield “hello” end
=> nil
irb> say_hello_to &method(:puts)
hello
=> nil
And you can also use a subclass of Proc.
class CachedProc < Proc
…
… and your example would work, I think.
Getting off-topic, if I may revisit your cached_proc again – you can
easily do without the class entirely.
def cached_proc &block
cache = Hash.new {|h, k| h[k] = block.call(*args) }
proc {|*args| cache[args] }
end
Cheers,
Dave
Dave B. wrote:
def cached_proc &block
cache = Hash.new {|h, k| h[k] = block.call(*args) }
proc {|*args| cache[args] }
end
I think it should be like this though:
def cached_proc(&block)
cache = Hash.new{|hsh, args| hsh[args] = block.call(*args)}
proc{|*args| cache[args]}
end
Daniel
On May 20, 2006, at 12:10 PM, [email protected] wrote:
Why isn’t it enough that it x responds to #call?
There’s a convention where to_XXX requires the receiver to return an
X instance while to_X doesn’t.
See [ruby-talk:96567].
–
Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant
On May 21, 2006, at 2:22 AM, Daniel S. wrote:
that responds to #call.
#to_ary requires you to return an Array.
#to_str requires you to return a String.
In this spirit #to_proc requires you to return a Proc.
–
Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant
Fair enough. But then where’'s my #to_p method
Fair enough. But then where’'s my #to_p method
On May 22, 2006, at 8:53 PM, [email protected] wrote:
Fair enough. But then where’'s my #to_p method
Huh? What are you responding to?
There’s no #to_p because there’s no use case for it.
–
Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant
[email protected] wrote:
P.S. Barring proof that there is no real usecase for it, I’ll make the
Hash#to_proc method available in the upcoming version of Facets.
Something like this, perhaps?
class Hash
def to_proc
proc{|obj| each{|key, value| obj.send("#{key}=", value)}}
end
end
(I know I’m annoying…)
Something like this, perhaps?
class Hash
def to_proc
proc{|obj| each{|key, value| obj.send("#{key}=", value)}}
end
end
Yep. Exaclty.
There were two use cases given in this thread. Whether there was a way
to do the same thing otherwise doesn not neccessarily deligitimize the
potential use.
To be more specific in my case I have a method:
class AClass
initialize( ¶ms )
params.call(self)
end
end
Configuration of the class needs to be settable either via a block:
AClass.new { |s|
s.conf = “whatever”
}
But also from an external hash-like object.
hl = HashLike.new( { :conf => ‘whatever’ } )
AClass.new( &hl )
But this later won’t work b/c of the Proc restriction. And, just as I
started this thread, I see no good reason that it should restrict.
Someone mentioned speed at one point, but that’s not Ruby’s modus
operandi --functionality is. A simple check for a “to_p” is reasonable
if the object isn’t a strict Proc.
Now you say there is no usecase. Lets look at my alternatives here. One
is to change the interface to accept both a hash-like object and a proc
–oh the joy:
initialize( paramsh={}, ¶ms )
raise "bugger" if paramsh and params
if params
params.call(self)
else
# this would have been the HashLike#call method
paramsh.each { |k,v| self.send("#{k}=",v) }
end
end
Okay, so something like that can work but it isn’t very OOP or DRY and
more importantly my use case is for something I want end-programmers to
be able to easily use to create there own “task interfaces” --this mess
just doesn’t cut it.
So here’s what I had to do to make it work for my usecase. Keeping the
original simple definition I added a method to the HashLike class such
that:
hl = HashLike.new( { :conf => ‘whatever’ } )
AClass.new( &(hl.to_proc) )
Ain’t it ironic. I had to take a hash, convert it to a proc, just so I
can turn around and convert it back to a set of attribute parameters.
Okay. So you say there’s no usecase. You’re younger than I, Eric, so
your mind is surely more supple. Maybe you are right. Maybe there’s a
better way to do this. Have any idea?
T.
P.S. Barring proof that there is no real usecase for it, I’ll make the
Hash#to_proc method available in the upcoming version of Facets.
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.
Sponsor our Newsletter | Privacy Policy | Terms of Service | Remote Ruby Jobs