Ruby and OOP-design (question of an old "procedural person" ;)

Consider inheritance: You should comply with the interface of the
superclass for substitutability. However, you may augment and extend it
as long as it is still possible to substitute a parent object with a
child object.

nonzero? just does this using core design decisions of Ruby (nil and
false are only false values) instead of classes.

That is a good point, yes.

Using the value of self feels
like relying on an undocumented side effect.

Now I know Ruby is easy to read, but we can’t have all the
documentation be Ruby source code. :slight_smile:
http://www.rubycentral.com/book/ref_c_numeric.html#Numeric.nonzero_qm

I know it’s documented - that’s why I said ‘feels’ :slight_smile:

(I feel the same way about
! methods returning nil rather than self when they haven’t made a
change).

Are you saying the usage of ? and ! should be restricted to only the two
protocols/types/interfaces? I.e.
? => result either true or false and

Yes

! => self if modified, nil if unmodified

! => self always. Frinstance, why can’t we have something like

Module Modified
def modified?
true
end
end

Module UnModified
def modified?
false
end
end

def method!
if changed?
self.extend(Modified)
else
self.extend(UnModified)
end
self
end

That would be a huge blow against the readability potential of Ruby
code, IMHO:

Real life:

  • “Have you found the answer to life, the universe and everything?”
  • “Yeah, it’s 42.”
    Ruby code:
    adams.found_answer? #=> 42

adams.found_answer? #=> true, false
adams.answer #=> 42, nil

Far more readable, IMO - in fact, it was the unintutive reading of a.nonzero?
that took me aback in the first place.

martin

···

Kent Dahl kentda+news@stud.ntnu.no wrote:

Well and good, but they don’t document the fact that the return value
can be used as anything other than a boolean. Duck typing or no, I find
it conceptually messy to have a method called nonzero? return self
rather than true - compare nil? and zero?. Using the value of self feels
like relying on an undocumented side effect.

But as long as it isn’t false or nil, it is true in effect.
And it’s far from undocumented.

I just said it felt like using an undocumented side effect, since it
embraces-and-extends what I’ve been thinking of as the implicit contract
of a ? method.

Yet in a way I sympathize… where I would feel funny is if
I made use of the numeric value returned rather than just
checking its truth… but I could probably get over even that.

And likewise it feels funny when I see it in someone else’s code. It may
be useful, but so are a lot of other things that didn’t make it into
ruby because the semantics conflicted with the name.

martin

···

Hal E. Fulton hal9000@hypermetrics.com wrote:

(I feel the same way about
! methods returning nil rather than self when they haven’t made a
change).

Are you saying the usage of ? and ! should be restricted to only the two
protocols/types/interfaces? I.e.
? => result either true or false and

Yes

! => self if modified, nil if unmodified

! => self always. Frinstance, why can’t we have something like

Module Modified
def modified?
true
end
end

Module UnModified
def modified?
false
end
end

def method!
if changed?
self.extend(Modified)
else
self.extend(UnModified)
end
self
end

That would be a huge blow against the readability potential of Ruby
code, IMHO:

Real life:

  • “Have you found the answer to life, the universe and everything?”
  • “Yeah, it’s 42.”
    Ruby code:
    adams.found_answer? #=> 42

adams.found_answer? #=> true, false
adams.answer #=> 42, nil

Far more readable, IMO - in fact, it was the unintutive reading of a.nonzero?
that took me aback in the first place.

But why should ? methods be required to return solely true or false?
Isn’t it enought to require that they
return objects that evaluate to true or false appropriately?

I agree that it’s all right to specify that ? methods shouldn’t be
required to return values other than true or
false, but I don’t think the opposite is true. What I’m saying is that
the return values of ? methods should
only be used in boolean situations, but they shouldn’t necessarily be
required to be booleans. Using the
return values as other than booleans would probably be considered
unsupported, since any object that
evaluated equivalently could be used to replace the current return value
and have the function act
equivalently for its intended purpose.

The only place you gain with having ? methods return solely true or
false is when you’re using irb, which
isn’t exactly for polished applications (correct me if I’m wrong), or if
you’re doing “puts blah?” directly,
in which case you should really be outputting a more coherent
error/diagnostic message anyway.

And if you go back to ruby and duck typing, if foo? returns something
that evaluates to true/false, then
it shouldn’t matter if it actually is true/false or not.

Cheers

  • Dan

I agree that it’s all right to specify that ? methods shouldn’t be
required to return values other than true or false, but I don’t think
the opposite is true. What I’m saying is that the return values of ?
methods should only be used in boolean situations, but they shouldn’t
necessarily be required to be booleans.

But there’s no way of enforcing the latter.

Using the return values as other than booleans would probably be
considered unsupported, since any object that evaluated equivalently
could be used to replace the current return value and have the
function act equivalently for its intended purpose.

Yes, except that it’s supported and used :slight_smile: If it were a hack someone
came up with I’d think it ugly, but be unbothered by it.

And if you go back to ruby and duck typing, if foo? returns something
that evaluates to true/false, then it shouldn’t matter if it actually
is true/false or not.

Yes if there’s a specific documented and relied-on non-‘true’ true
value. Not sure why I feel so prescriptive about this issue, but I find
the whole thing very nonRubyish in the way it tries to pack two pieces
of information into a single primitive value.

martin

···

Dan Doel djd15@po.cwru.edu wrote:

Hi –

But why should ? methods be required to return solely true or false?
Isn’t it enought to require that they
return objects that evaluate to true or false appropriately?

Jumping in with semi-devil’s-advocate point:

One situation I can think of in which it would be handy to rely on this
would be:

if a.nil? == b.nil?

which of course could also be written:

if (a.nil? && b.nil?) ||! (a.nil? || b.nil?)

or something, but obviously version 1 is nice and concise. Then again,
it’s a pretty marginal case, I guess.

David

···

On Sun, 10 Aug 2003, Dan Doel wrote:

–
David Alan Black
home: dblack@superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

Hi –

And if you go back to ruby and duck typing, if foo? returns something
that evaluates to true/false, then it shouldn’t matter if it actually
is true/false or not.

Yes if there’s a specific documented and relied-on non-‘true’ true
value. Not sure why I feel so prescriptive about this issue, but I find
the whole thing very nonRubyish in the way it tries to pack two pieces
^^^^^^^^^^
(You mean non_Rubyish, of course :slight_smile:

of information into a single primitive value.

But isn’t that true of all values in Ruby? Meaning, they all pack
boolean information intor themselves along with whatever else they
are.

David

···

On Sun, 10 Aug 2003, Martin DeMello wrote:

Dan Doel djd15@po.cwru.edu wrote:

–
David Alan Black
home: dblack@superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

dblack@superlink.net wrote:

Hi –

But why should ? methods be required to return solely true or false?
Isn’t it enought to require that they
return objects that evaluate to true or false appropriately?

Jumping in with semi-devil’s-advocate point:

One situation I can think of in which it would be handy to rely on this
would be:

if a.nil? == b.nil?

which of course could also be written:

if (a.nil? && b.nil?) ||! (a.nil? || b.nil?)

or something, but obviously version 1 is nice and concise. Then again,
it’s a pretty marginal case, I guess.

David

That is a good example.

Does ruby not have exclusive or? I can’t remember at the moment. If it
did, I think the top is the same
as:

unless a.nil? ^ b.nil?

Which is still somewhat unclear, I agree.

That’s a good example, though.

  • Dan
···

On Sun, 10 Aug 2003, Dan Doel wrote:

Martin DeMello wrote:

I agree that it’s all right to specify that ? methods shouldn’t be
required to return values other than true or false, but I don’t think
the opposite is true. What I’m saying is that the return values of ?
methods should only be used in boolean situations, but they shouldn’t
necessarily be required to be booleans.

But there’s no way of enforcing the latter.

There’s no static way of enforcing that ? methods can only return
booleans, either, since variables
are untyped in ruby. And since ? is just an extra symbol for including
in method names, I don’t
think the interpreter should fail, since someone could be strange an do
something like

obj.what_is_a?

Which is ugly to you and me, but someone else might like it, I suppose.
:slight_smile: All I’m saying is that
in either case, it’s merely a convention either way, and people may
adhere to it or not.

Using the return values as other than booleans would probably be
considered unsupported, since any object that evaluated equivalently
could be used to replace the current return value and have the
function act equivalently for its intended purpose.

Yes, except that it’s supported and used :slight_smile: If it were a hack someone
came up with I’d think it ugly, but be unbothered by it.

Well, it shouldn’t be used (probably). Go back and read my final post
on the duck typing thread;
I think it applies here. If a method’s contract says, “returns a value
that is true or false depending
on blah” then the contract only guarantees true or false, so nothing
more can be used correctly.
If it says, “returns self when true, and nil when false,” then those
values can be used correctly. If
it says, “returns true when true, and false when false,” then you’re
enforcing that programatically.

The ? doesn’t define the contract, the person writing the method does.

And if you go back to ruby and duck typing, if foo? returns something
that evaluates to true/false, then it shouldn’t matter if it actually
is true/false or not.

Yes if there’s a specific documented and relied-on non-‘true’ true
value. Not sure why I feel so prescriptive about this issue, but I find
the whole thing very nonRubyish in the way it tries to pack two pieces
of information into a single primitive value.

I don’t know that it’s non-rubyish, but it is non-object oriented, in
some sense. Or perhaps not
non-object oriented, but it flies in the face of some standard of
“language purity.” But ruby
already does that anyway by treating nil and false as false, and
everything else as true.

If the contract of ? methods is that they always return a true-value
when the condition is true,
or a false-value when the condition is false, then it doesn’t really
make sense to return anything
other than true or false themselves (other than to save typing, because:

def nil?
   self
end

is shorter than

def nil?
   self ? true : false;
end

But that’s not much of an argument). However, that may not always be
the explicit contract
of a ? method. Perhaps the convention needs to be changed, or perhaps
you need to re-
evaluate your concept of ? methods. That’s not really for me to say one
way or the other.
However, I will say that if ? methods are meant to only be used as true
or false values,
then it shouldn’t matter whether the values returned actually are true
or false (except in certain
circumstances where the fact that they aren’t can be a real pain; see
David’s devil’s advocate
post), and that concept is very rubyish.

  • Dan
···

Dan Doel djd15@po.cwru.edu wrote:

dblack@superlink.net wrote:

Yes if there’s a specific documented and relied-on non-‘true’ true
value. Not sure why I feel so prescriptive about this issue, but I find
the whole thing very nonRubyish in the way it tries to pack two pieces
^^^^^^^^^^
(You mean non_Rubyish, of course :slight_smile:

of course :slight_smile: or even non_rubyish

of information into a single primitive value.

But isn’t that true of all values in Ruby? Meaning, they all pack
boolean information intor themselves along with whatever else they
are.

Not really - the boolean information usually acts as an existence test
for the value. Here, by the semantics of nonzero?, the value is a
boolean, so packing another value in for the sake of convenience feels
wrong. IMO, this would be better in a ‘nonzero’ method (as opposed to
‘nonzero?’), reading ‘a.nonzero?’ as ‘is a nonzero?’ and ‘a.nonzero’ as
‘return the nonzero part of a’ (by analogy with, say, Complex#im). Then
if a is zero, the nonzero part of a could safely be said to be nil, and
in a boolean context it’d be a proper existence test, and I at least
would be happy :slight_smile:

martin

Hi –

One situation I can think of in which it would be handy to rely on this
would be:

if a.nil? == b.nil?

which of course could also be written:

if (a.nil? && b.nil?) ||! (a.nil? || b.nil?)

or something, but obviously version 1 is nice and concise. Then again,
it’s a pretty marginal case, I guess.

David

That is a good example.

Does ruby not have exclusive or? I can’t remember at the moment. If it
did, I think the top is the same
as:

unless a.nil? ^ b.nil?

Which is still somewhat unclear, I agree.

I, however, no long agree with myself :slight_smile: I just forgot about ^.

That’s a good example, though.

Hmmm… I wonder if it could be strengthened by finding a case where
there actually isn’t an equally short (or shorter) alternative. I
can’t think of one. Of course, as I mentioned, I’ve sort of playing
devil’s advocate – I don’t think the non-true-or-false return value
actually bothers me.

David

···

On Mon, 11 Aug 2003, Dan Doel wrote:

dblack@superlink.net wrote:

–
David Alan Black
home: dblack@superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

    def nil?
       self
    end

Sorry, but I really don't understand why you use #nil? because precisely
#nil? return true or false

The original problem was with #nonzero?

pigeon% ruby -e 'p 12.nonzero?'
12
pigeon%

pigeon% ruby -e 'p 12.zero?'
false
pigeon%

Guy Decoux

However ^ is overloaded, so although it works when comparing false/true with
false/true, it doesn’t with other things; especially since it doubles up as
a bitwise numeric operator too.

irb(main):001:0> 5 ^ false
TypeError: cannot convert false into Integer
from (irb):1:in `^’
from (irb):1

But it does treat ‘nil’ as ‘false’. So you could say:

 if  (a && true) ^ (b && true)
   ...
 end

which tests if both a and b are ‘true’ or both a and b are ‘false’ in the
Ruby sense of those terms, but it’s still not very pretty. I think it would
be clearer to write

 if  (a && b) || (!a && !b)

It’s not a problem with nil? anyway. If you want to check whether a and b
are either both zero or both nonzero, you could do

 if (a == 0) == (b == 0)
   ...
 end

The fact that nonzero? carries forward the original value, rather than just
‘true’, is IMO a nice touch which allows useful chaining of operations like
cmp. But that’s just being pragmatic :slight_smile:

Cheers,

Brian.

···

On Mon, Aug 11, 2003 at 02:02:33AM +0900, dblack@superlink.net wrote:

Does ruby not have exclusive or? I can’t remember at the moment. If it
did, I think the top is the same
as:

unless a.nil? ^ b.nil?

Which is still somewhat unclear, I agree.

I, however, no long agree with myself :slight_smile: I just forgot about ^.

ts wrote:

“D” == Dan Doel djd15@po.cwru.edu writes:

def nil?
   self
end

Sorry, but I really don’t understand why you use #nil? because precisely
#nil? return true or false

The original problem was with #nonzero?

pigeon% ruby -e ‘p 12.nonzero?’
12
pigeon%

pigeon% ruby -e ‘p 12.zero?’
false
pigeon%

It was just an example. #nil? could be written that way, although then
it’d be pointless, since

if  obj ...

Would be exactly the same as

if obj.nil? ...

The only difference would be some readability.

But you could substitute #nonzero?, #zero?, #respond_to?, or any ?
method for #nil? in my
post and I think it would still apply, except that you don’t save any
typing for other methods.

  • Dan

Brian Candler wrote:

Does ruby not have exclusive or? I can’t remember at the moment. If it
did, I think the top is the same
as:

unless a.nil? ^ b.nil?

Which is still somewhat unclear, I agree.

I, however, no long agree with myself :slight_smile: I just forgot about ^.

However ^ is overloaded, so although it works when comparing false/true with
false/true, it doesn’t with other things; especially since it doubles up as
a bitwise numeric operator too.

irb(main):001:0> 5 ^ false
TypeError: cannot convert false into Integer
from (irb):1:in `^’
from (irb):1

But it does treat ‘nil’ as ‘false’. So you could say:

if  (a && true) ^ (b && true)
  ...
end

which tests if both a and b are ‘true’ or both a and b are ‘false’ in the
Ruby sense of those terms, but it’s still not very pretty. I think it would
be clearer to write

if  (a && b) || (!a && !b)

It’s not a problem with nil? anyway. If you want to check whether a and b
are either both zero or both nonzero, you could do

if (a == 0) == (b == 0)
  ...
end

Yeah, I thought of the problem with ^ on the way to lunch.

And I just checked and there’s no “xor” equivalent to “and” “or” and
“not”, so you can’t work around it
that way.

Perhaps an “xor” keyword (or a ^^ logical xor operator) would be handy
to have specifically for this
kind of situation, since there’s no way to conveniently do (obj1 xor
obj2) in existance tests.

Then again, I can’t think of any places where you’d need to do that.

  • Dan
···

On Mon, Aug 11, 2003 at 02:02:33AM +0900, dblack@superlink.net wrote:

Dan Doel wrote:

It was just an example. #nil? could be written that way, although then
it’d be pointless, since

if obj …

Would be exactly the same as

if obj.nil? …

The only difference would be some readability.

… and the special case where obj==false.

···

–
([ Kent Dahl ]/)_ ~ [ Kent Dahl - Kent Dahl ]/~
))_student_/(( _d L b_/ (pre-) Master of Science in Technology )
( __õ|õ// ) )Industrial economics and technological management(
_
/ö____/ (_engineering.discipline=Computer::Technology)

Scripsit ille »Brian Candler« B.Candler@pobox.com:

Does ruby not have exclusive or? I can’t remember at the moment. If it
did, I think the top is the same
as:

unless a.nil? ^ b.nil?

Which is still somewhat unclear, I agree.

I, however, no long agree with myself :slight_smile: I just forgot about ^.

However ^ is overloaded, so although it works when comparing false/true with
false/true, it doesn’t with other things; especially since it doubles up as
a bitwise numeric operator too.

BTW: why do all C-like languages lack the ^^ operator (boolean XOR)?

irb(main):001:0> 5 ^ false
TypeError: cannot convert false into Integer
from (irb):1:in `^’
from (irb):1

But it does treat ‘nil’ as ‘false’. So you could say:

 if  (a && true) ^ (b && true)

if !a ^ !b # since a xor b == (not a) xor (not b)

Well, my common C idioms for this case are:

boolean XOR: !a ^ !b
obfuscated boolean XOR: !a!=!!!b /* no, I am not using that */
convert to boolean: !!a

They all work in Ruby.

···

On Mon, Aug 11, 2003 at 02:02:33AM +0900, dblack@superlink.net wrote:

–
L: Núper erát medicús nunc ést vispíllo Diáulus:
D: Früher war er Arzt, nun ist Diaulus Totengräber:
L: Quód vispíllo facít - fécerat ét medicús.
D: Was er als Totengräber macht - tat er schon als Arzt. [Martial]

I think you mean ‘if obj.notnil?’ could be written that way.

 if obj...

is equivalent to

 unless obj.nil? ...

with the exception of obj == false.

Cheers,

Brian.

···

On Mon, Aug 11, 2003 at 03:16:55AM +0900, Dan Doel wrote:

It was just an example. #nil? could be written that way, although then
it’d be pointless, since

if obj …

Would be exactly the same as

if obj.nil? …

Rudolf Polzer wrote:

Scripsit ille »Brian Candler« B.Candler@pobox.com:

Does ruby not have exclusive or? I can’t remember at the moment. If it
did, I think the top is the same
as:

unless a.nil? ^ b.nil?

Which is still somewhat unclear, I agree.

I, however, no long agree with myself :slight_smile: I just forgot about ^.

However ^ is overloaded, so although it works when comparing false/true with
false/true, it doesn’t with other things; especially since it doubles up as
a bitwise numeric operator too.

BTW: why do all C-like languages lack the ^^ operator (boolean XOR)?

I’m no expert, but I suspect it’s because ^ and ^^ do the same thing.

The big reason for & and && is that && is lazy, while & evaluates all
its arguments. Otherwise
you could always use & and overload it for use with integers and booleans.

^ always has to know the values of both arguments, so it can never be
lazy, so there’s no point
in having two, except in Ruby’s case where ^ can be overloaded, and ^^
would be useful to
coerce both arguments to booleans.

  • Dan
···

On Mon, Aug 11, 2003 at 02:02:33AM +0900, dblack@superlink.net wrote:

Brian Candler wrote:

It was just an example. #nil? could be written that way, although then
it’d be pointless, since

if obj …

Would be exactly the same as

if obj.nil? …

I think you mean ‘if obj.notnil?’ could be written that way.

if obj...

is equivalent to

unless obj.nil? ...

with the exception of obj == false.

Cheers,

Brian.

Right, of course. Most of the time it would be

def nil?
!self
end

Which would be a boolean anyway.

Of course, it’s even simpler than that, because you can do:

class Object
def nil?
false
end
end

class NilClass
def nil?
true
end
end

So you really never save any typing at all. #nil? is a bad
example, it seems.

  • Dan
···

On Mon, Aug 11, 2003 at 03:16:55AM +0900, Dan Doel wrote:

The big reason for & and && is that && is lazy, while & evaluates all
its arguments.

In what language(s)? I think that’s the case in Java, but not in C/C++ if I
recall correctly, which I might not.