How to react on nil or wrong object-type as parameter

D

Daniel Schierbeck

Eric said:
#to_str is not for type conversion. It exists for classes that duck
type completely to String and is called when a C string is needed by a
method in String to improve performance. In other words, #to_str should
only be implemented on objects that are already "Strings".

Exactly my point. I think we're misunderstanding each other here; if you
have an object that is a representation of a string, say

# Bad example, but hey...
class Name
attr_accessor :first, :last

def initialize(first, last)
@first, @last = first, last
end
end

Then it's okay for it to have #to_str, e.g.

def to_str
"#{first} #{second}"
end

My own logic is this: if an object is a natural string, but with *more*
information, then it can have #to_str. Otherwise, stick to #to_s.

A much better example is the one brought up on the list not long ago:

class RomanNumeral
def initialize(num)
@num = num.to_int
end

# this really is an integer
def to_int
@num
end

# but there's not much sense in manipulating
# it as a string
def to_s
...
end
end

If it were for a real application, I'd just implement an
Integer#to_roman method, but I still think this is a good example.
#to_s is for type conversion. Trust your users to provide a meaningful
#to_s. Don't force them to inappropriately implement #to_str.

I agree wholeheartedly. I'm just bad at writing.
 
E

Eric Hodel

Exactly my point. I think we're misunderstanding each other here;
if you have an object that is a representation of a string, say

# Bad example, but hey...
class Name
attr_accessor :first, :last

def initialize(first, last)
@first, @last = first, last
end
end

Then it's okay for it to have #to_str, e.g.

def to_str
"#{first} #{second}"
end

My own logic is this: if an object is a natural string, but with
*more* information, then it can have #to_str. Otherwise, stick to
#to_s.

A Name is not a String. You don't #each it, you don't #chop it, its
never #empty?, ...
 
D

Daniel Schierbeck

Eric said:
A Name is not a String. You don't #each it, you don't #chop it, its
never #empty?, ...

That's why you use the return value of #to_str. If only String had
#to_str, then why have it in the first place? Why not just check the class?

I'm not saying this is how everybody should do it, I'm just saying that
it's a very smart way to handle types -- duck typing being a very
similar way.


Cheers,
Daniel
 
E

Eric Hodel

That's why you use the return value of #to_str.

You don't call #to_str, String calls #to_str when it needs to.
If only String had #to_str, then why have it in the first place?
Why not just check the class?

It would be appropriate to define #to_str for objects that really are
Strings, but don't inherit from String. A good example would be when
writing a bridge to another language, like Java strings or C# strings.
I'm not saying this is how everybody should do it, I'm just saying
that it's a very smart way to handle types -- duck typing being a
very similar way.

It isn't a smart way to handle types, it is a broken and wrong way to
handle types.

Don't confuse "duck types to String" with "has a String
representation (#to_s)". I doubt you will ever mean to say the former.
 
D

Daniel Schierbeck

Eric said:
You don't call #to_str, String calls #to_str when it needs to.

So the implementation of e.g. String#+ is wrong? Or is it okay for a
method on String to call #to_str on its arguments?
It isn't a smart way to handle types, it is a broken and wrong way to
handle types.

I'm sorry, but I have to disagree. Read the RomanNumeral example again
-- it's an integer, but it doesn't inherit from Integer.


Daniel
 
E

Eric Hodel

So the implementation of e.g. String#+ is wrong? Or is it okay for
a method on String to call #to_str on its arguments?

I suggest you read through the archives to discover when to use
#to_str and when to use #to_s. I've linked to matz' discussion of
the matter several times. The short version is, if you call #to_str
or implement #to_str you are probably doing something wrong.
I'm sorry, but I have to disagree. Read the RomanNumeral example
again -- it's an integer, but it doesn't inherit from Integer.

Numeric duck types use #coerce because #to_int won't cover all the
bases. See the earlier thread on #to_i vs #to_int, and try:

5 + Roman.new(6)

You'll find that #to_int does not do anything for you.

This is why you shouldn't call or define #to_xxx methods, how and
where they are supposed to be used is confusing, convoluted and error-
prone. They aren't supposed to be used where you think they are
supposed to be used.

PS:

I can't think of a legitimate reason to define a RomanNumeral class.
It would be easier to add Integer#to_roman that returns a String and
Kernel#Roman that parses a String into an Integer.

For bonus points, define #const_missing to parse a constant that is
also a Roman numeral.
 
R

Robert Klemme

I sort of agree to both of you and I think despite this thread you maybe
not too far away from each other.

Numeric duck types use #coerce because #to_int won't cover all the
bases. See the earlier thread on #to_i vs #to_int, and try:

5 + Roman.new(6)

You'll find that #to_int does not do anything for you.

But *if* you define a class Roman #to_int should be part of it because a
roman can actually be treated as an integer. Of course you'll also have
to implement #coerce and probably several others.
This is why you shouldn't call or define #to_xxx methods, how and where
they are supposed to be used is confusing, convoluted and error-prone.
They aren't supposed to be used where you think they are supposed to be
used.

I agree that implementing and invoking #to_int and #to_str needs
considerably more consideration than their counterparts #to_i and #to_s
- and you'll rarely see them implemented.

The standard lib has several classes which define these methods: you can
try it out:

ruby -e '%w{to_int to_str}.each {|mn| print "\nMethod ", mn, ":\n";
ObjectSpace.each_object(Module) {|cl| p cl if cl.instance
_methods.any? {|m| mn == m}}}'
I can't think of a legitimate reason to define a RomanNumeral class. It
would be easier to add Integer#to_roman that returns a String and
Kernel#Roman that parses a String into an Integer.

IMHO you can take at least two different positions here - which one is
more appropriate probably depends on the problem to solve. You can view
a roman number as another representation of an integer value. In that
case Erik's approach is more appropriate. You can as well view a roman
number as something specific if it has properties that are not covered
by standard integer classes. In that case it deserves a class of its
own including #to_i, #to_int, #coerce, #eql?, #==, #hash, #<=>, #to_s
and maybe more.

Kind regards

robert
 
E

Eric Hodel

I sort of agree to both of you and I think despite this thread you
maybe not too far away from each other.



I agree that implementing and invoking #to_int and #to_str needs
considerably more consideration than their counterparts #to_i and
#to_s - and you'll rarely see them implemented.

The standard lib has several classes which define these methods:
you can try it out:

ruby -e '%w{to_int to_str}.each {|mn| print "\nMethod ", mn, ":\n";
ObjectSpace.each_object(Module) {|cl| p cl if cl.instance
_methods.any? {|m| mn == m}}}'

In 1.9, Exception no longer implements #to_str, leaving only String
and NameError::message.
 
R

Rick DeNatale

Some of the folks here might want to take a look at an article I just
posted to my blog about the subtleties of duck types:
http://talklikeaduck.denhaven2.com/articles/2006/08/10/ducks-can-be-subtle-birds

I started this ruby oriented blog a week or so ago, partially prompted
by the "I'll Have the Duck" thread here. I've been a little reluctant
to expose it since it's hosted on my home server, which I'm still
trying to get completely back to speed after an Ubuntu upgrade which
didn't go completely well.
 

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
474,209
Messages
2,571,088
Members
47,687
Latest member
IngridXxj

Latest Threads

Top