Oppinions on RCR for dup on immutable classes

G

Gregory Brown

If we see a class as a restaurant, your illustration makes sense. But
from my point of view, we don't know the name of the restaurant, nor
its menu. We just sit and cry for "Spaghetti!", and sometimes the
waiter says "I'm sorry".

But they never do seem to run out of chunky bacon.
 
S

Stefan Rusterholz

unknown said:
yes - for illustration ;-)

And in a real situation, why would you chose to do so? What would be the
reasoning to justify that?
this is a side effect of strong dynamic type systems

I am well aware of that. I used ruby for over a year ;-)
But you in this situations you have two options, define a method whichs
only code is "raise Exception" or not define the method at all.
Or in your example the choice is between redefining the method with one
whichs only code is "raise Exception" or undefine the existing one.
In both situations: why would you chose one over the other?
I'm sorry if I'm obnoxious with that :)

My regards
 
S

Stefan Rusterholz

Yukihiro said:
Hi,

In message "Re: Oppinions on RCR for dup on immutable classes"
on Sun, 18 Feb 2007 01:37:19 +0900, Stefan Rusterholz

|Um, no, with the classes mentioned in the RCR the answer would be
|"never", not just "today". You'd have to buy the Restaurant and exchange
|to cook to change the answer :)

If we see a class as a restaurant, your illustration makes sense. But
from my point of view, we don't know the name of the restaurant, nor
its menu. We just sit and cry for "Spaghetti!", and sometimes the
waiter says "I'm sorry".

matz.

The example translates to:
Restaurant := Class
Menucard := #methods
Say "we don't serve that" := raised Exception

If it changes from time to time I agree with you. But if it is "never",
the restaurant shouldn't put the menu on the card in the first time - in
my oppinion :)

My regards
 
D

dblack

Hi --

The example translates to:
Restaurant := Class
Menucard := #methods
Say "we don't serve that" := raised Exception

But methods are not constrained by class. It's not the class's
responsibility to oversee the object's methods. I'm not sure where
the object fits into your model.


David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)
 
S

SonOfLilit

Oh, good point.

=> true

Then you need to rescue the exception.

If you *really* need this behaviour, you could just stick it in a file
somewhere and require it.

NoMethodError: undefined method `dup' for 2:Fixnum
Oh no, you don't wanna do that: What if you're a library and a user
assumes :dup is defined? What if you use a library that assumes it and
don't know about it?
 
G

Gregory Brown

Oh no, you don't wanna do that: What if you're a library and a user
assumes :dup is defined? What if you use a library that assumes it and
don't know about it?

Um. then no one uses your library?

I've already made it clear I don't think it's a good idea in the
general sense, I'm just saying that if the behaviour change is
necessary or important to you, it's easy to add.

Whether or not it's good practice is an entirely seperate question.
I would be tempted to bludgeon library writers who find it convenient
to undef core methods, to be honest.

For client code that doesn't have to play nice with others? Have at
it! (You *are* writing tests that make sure your code is working
right, aren't you? :) )
 
A

ara.t.howard

And in a real situation, why would you chose to do so? What would be the
reasoning to justify that?

the one that springs to mind is

module Mixin
def average
total.to_f / n.to_f
end
def total
raise NotImplementedError
end
def n
raise NotImplementedError
end
end

this give a much nicer error than NameError or something about nil not
responding to 'to_f'.

another is

module DRbUndumped
def _dump(dummy) # :nodoc:
raise TypeError, 'can\'t dump'
end
end

this is more useful than it looks. what it means is that any object in a
hierarchy will cause a particular exception to get thrown, indicating that a
drb proxy should be used. this is a good approach because you can mark objects
which are normally able to be marshaled as not being so in a way that's viral
to other objects holding references to this object.
I am well aware of that. I used ruby for over a year ;-)

sorry for being pendantic then.
But you in this situations you have two options, define a method whichs
only code is "raise Exception" or not define the method at all.
Or in your example the choice is between redefining the method with one
whichs only code is "raise Exception" or undefine the existing one.
In both situations: why would you chose one over the other?
I'm sorry if I'm obnoxious with that :)

that's ok.

cheers.

-a
 
S

Stefan Rusterholz

unknown said:
the one that springs to mind is

module Mixin
def average
total.to_f / n.to_f
end
def total
raise NotImplementedError
end
def n
raise NotImplementedError
end
end

this give a much nicer error than NameError or something about nil not
responding to 'to_f'.

module Mixin
def average
total().quo(n())
end
end

a) uses Rational if possible ;-p (ok, besides the point)
b) no superfluous code
c) no additional exception

I'm sorry, I still fail to see the point in defining a method that says
the method can't be executed (put a menu that isn't actually served on
the menucard - put it on the menucard when it is served)

My regards
 
G

Gregory Brown

module Mixin
def average
total().quo(n())
end
end

a) uses Rational if possible ;-p (ok, besides the point)
b) no superfluous code
c) no additional exception

I'm sorry, I still fail to see the point in defining a method that says
the method can't be executed (put a menu that isn't actually served on
the menucard - put it on the menucard when it is served)

the difference is in the rescue.

rescue NoMethodError

is not the same thing as

rescue NotImplementedError
 
S

Stefan Rusterholz

Gregory said:
the difference is in the rescue.

rescue NoMethodError

is not the same thing as

rescue NotImplementedError

That's getting off-topic. The error dup gives is "not possible", not
"not implemented". Different story.
If you check previous messages you might figure that I can understand
the use in abstract classes (or mixins here) even though I'd do it
differently.

My regards.
 
D

Dean Wampler

...
OO Languages are Class oriented languages
Dynamic Languages are Object oriented languages.
Replace Class with Type and you see what I mean.

This is all very much IMHO of course but I feel that the Ruby
community has made me evolve a lot away from "Class oriented".

Interesting points, especially about the implications of
"class-centric" vs. "object-centric" programming.

It's true that I rarely ever run into LSP issues, even in Java code. I
think it reflects, in part, the general movement OOD towards
de-emphasizing inheritance in favor of composition through
abstractions, etc. I would rather have the richness of Object and
Kernel, even with some LSP issues.

As someone else commented, perhaps the real issue is that
5.respond_to?:)dup) returns true yet 5.dup raises, so you have no way
of knowing in advance that you shouldn't call dup.
 
A

ara.t.howard

As someone else commented, perhaps the real issue is that
5.respond_to?:)dup) returns true yet 5.dup raises, so you have no way of
knowing in advance that you shouldn't call dup.

i simply do not understand this line of thinking - every call to every object
always has that characteristic

f.respond_to? :read #=> true
f.gets # EOFError

q.respond_to? :pop #=> true
q.pop(true) #=> ThreadError if empty

to me this really seems like a dynamic vs static issue - i just don't see how
ruby can save you, regardless of the impl of dup, or any other method. one
cannot avoid hanlding runtime exceptions in a dynamic language. one cannot
know in advance whether it's ok to call something - even if the object
responds to it.

regards.

-a
 
A

ara.t.howard

i simply do not understand this line of thinking - every call to every object
always has that characteristic

f.respond_to? :read #=> true
f.gets # EOFError

q.respond_to? :pop #=> true
q.pop(true) #=> ThreadError if empty

to me this really seems like a dynamic vs static issue - i just don't see how
ruby can save you, regardless of the impl of dup, or any other method. one
cannot avoid hanlding runtime exceptions in a dynamic language. one cannot
know in advance whether it's ok to call something - even if the object
responds to it.

... or even if it doesn't: method_missing

-a
 
G

Gregory Brown

That's getting off-topic. The error dup gives is "not possible", not
"not implemented". Different story.
If you check previous messages you might figure that I can understand
the use in abstract classes (or mixins here) even though I'd do it
differently.

Actually, My point was about expressiveness through exceptions.
That is what you seem to be missing
TypeError: can't dup Fixnum
from (irb):1:in `dup'
from (irb):1

TypeError is different than NoMethodError. In this case, it is
expressive of what is actually going wrong. Again, the difference is
in the rescue.
 
G

Gregory Brown

one cannot
know in advance whether it's ok to call something - even if the object
responds to it.

With this in mind, what do you guys think of this work around?
[sandal@metta payroll_camping]$ irb
class Object
def dup?
dup
rescue TypeError
false
end
end => nil
3.dup? => false
3.dup? || 3 => 3
"foo".dup?
=> "foo"
 
D

dblack

Hi --

one cannot
know in advance whether it's ok to call something - even if the object
responds to it.

With this in mind, what do you guys think of this work around?
[sandal@metta payroll_camping]$ irb
class Object
def dup?
dup
rescue TypeError
false
end
end => nil
3.dup? => false
3.dup? || 3 => 3
"foo".dup?
=> "foo"

false.dup? # => false :)

I'm not sure what I think of it. I'm trying to think of how it would
be used, given that it's a ?-method that returns something other than
true/false. Would you do this, for example:

if (d = x.dup?)

I'm not sure that reads very well; it really kind of conceals the fact
that d might be an actual dup of x (at least to my eyes). But I'm
probably not thinking of all the places it might be used.


David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)
 
R

Robert Dober

Interesting points, especially about the implications of
"class-centric" vs. "object-centric" programming.

It's true that I rarely ever run into LSP issues, even in Java code. I
think it reflects, in part, the general movement OOD towards
de-emphasizing inheritance in favor of composition through
abstractions, etc. I would rather have the richness of Object and
Kernel, even with some LSP issues.
Interesting - and comforting - to know.
I do not have the luxury to follow more than Ruby nowadays (and I try
to find time for Smalltalk very hard, in vein so far).
As someone else commented, perhaps the real issue is that
5.respond_to?:)dup) returns true yet 5.dup raises, so you have no way
of knowing in advance that you shouldn't call dup.
That just came up recently and I agree that this is kind of inelegant
(euphemistically)
Maybe that would be a reasonable CR?
Cheers
Robert
 
D

dblack

Hi --

That just came up recently and I agree that this is kind of inelegant
(euphemistically)
Maybe that would be a reasonable CR?

See Ara's answer to Dean, though. respond_to? isn't designed to tell
you what will happen when you call the method. Lots of objects
respond to methods by raising exceptions.

Maybe the reason people don't like dup doing that is that it *always*
does it for some classes of object. But I think that's in order to
leave no mysteries. dup is "advertised", so to speak, as something
that every object can do. So when an object can't do it, it's more
gracious to explain why not (in the exception message).

It's a lot like this:

irb(main):001:0> (0..10).to_a
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
irb(main):002:0> (0.0..10.0).to_a
TypeError: can't iterate from Float

Ranges with floats in them could just undef to_a and not respond, but
the expectation exists that all ranges have some meaningful
relationship to the process of being converted into an array
(including the relationship of opting out of it but in a way that
tells you what's going on).

I realize that two ranges are of the same class while, say, a string
and nil aren't. But it's not a class thing; it's more about
collective (not necessary along class lines) behaviors and
expectations.


David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)
 

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

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top