Forum: Ruby Oppinions on RCR for dup on immutable classes

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Cf7cd97cdc8ed7d4ae92965b24f0dfad?d=identicon&s=25 Stefan Rusterholz (apeiros)
on 2007-02-16 00:46
I'm about to make this RCR and would like to get some oppinions on it in
order to make my decision.
The questions are:
1) Should I split this RCR up for a) and b)?
2) Should I only submit a single one, if so, which one?
3) Should I submit this RCR at all?
4) Oppinions, suggestions, ideas... everything welcome :)

Abstract:
  Change behaviour of dup in immutable classes.

Problem:
  dup on immutable classes (NilClass, FalseClass, TrueClass, Fixnum,
Symbol)
  raises an Exception.

Proposal:
  a) Remove the dup method from NilClass, FalseClass, TrueClass, Fixnum,
Symbol
  b) Let dup in NilClass, FalseClass, TrueClass, Fixnum, Symbol return
self

Analysis:
  This may be a minor glitch in the ruby API, but with the advent or
Ruby2 it
  might be worth changing.
  a) should only in rare circumstances break existing code as dup for
the cases
  in question already throws an exception and it would only break if the
rescue
  would fail due to the changed exception class. It would restore the
behaviour
  that a class only implements methods it can actually execute, which
also means
  testing via respond_to? is possible.
  b) would let the immutability of the classes be an implementation
detail (which
  would be consistent with behaviour of other immutable classes like
Time e.g.).
  It shouldn't break existing code as the it is the usual fallback.

Implementation:
  a)
  [NilClass, FalseClass, TrueClass, Fixnum, Symbol].each { |klass|
    klass.send(:undef_method, :dup) { self }
  }
  b)
  [NilClass, FalseClass, TrueClass, Fixnum, Symbol].each { |klass|
    klass.send(:define_method, :dup) { self }
  }

My regards
852a62a28f1de229dc861ce903b07a60?d=identicon&s=25 Gavin Kistner (phrogz)
on 2007-02-16 00:55
(Received via mailing list)
On Feb 15, 4:46 pm, Stefan Rusterholz <apei...@gmx.net> wrote:
> 1) Should I split this RCR up for a) and b)?
> 2) Should I only submit a single one, if so, which one?

You should only submit one. The discussion of which choice is better
is appropriate on the mailing list, IMO. When you feel that a
consensus has been reached, submit that one as an RCR.

Personally, I would lean towards option (b).

> Problem:
>   dup on immutable classes (NilClass, FalseClass, TrueClass, Fixnum,
> Symbol)
>   raises an Exception.

That's a statement of fact, but doesn't explain *why* it's a problem,
or (important for an RCR) why it needs to be fixed in the core of the
language.

What is the use case that is prevented by the problem? What does it
make inconvenient? Why should it be changed?
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2007-02-16 07:55
(Received via mailing list)
Hi,

In message "Re: Oppinions on RCR for dup on immutable classes"
    on Fri, 16 Feb 2007 08:55:12 +0900, "Phrogz" <gavin@refinery.com>
writes:

|That's a statement of fact, but doesn't explain *why* it's a problem,
|or (important for an RCR) why it needs to be fixed in the core of the
|language.
|
|What is the use case that is prevented by the problem? What does it
|make inconvenient? Why should it be changed?

Seconded.  It pretty trivial for us core developers to make dup for
immutable objects to return themselves, but _I_ don't understand why
it is needed.  I assume obj.object_id != obj.dup.object_id, and see no
good reason enough to break the assumption.

              matz.
31e038e4e9330f6c75ccfd1fca8010ee?d=identicon&s=25 Gregory Brown (Guest)
on 2007-02-16 15:43
(Received via mailing list)
On 2/16/07, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:
> |make inconvenient? Why should it be changed?
>
> Seconded.  It pretty trivial for us core developers to make dup for
> immutable objects to return themselves, but _I_ don't understand why
> it is needed.  I assume obj.object_id != obj.dup.object_id, and see no
> good reason enough to break the assumption.

+1. If i am trying to dup an object, sometimes it's inconvenient that
it complains,
but most of the time i want to know about it.

I also don't think something like 5.dup has semantic meaning.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2007-02-16 16:23
(Received via mailing list)
On Fri, 16 Feb 2007, Gregory Brown wrote:

>
> I also don't think something like 5.dup has semantic meaning.
>

unlike 42.dup, which is patently obivous.

-a
Cf7cd97cdc8ed7d4ae92965b24f0dfad?d=identicon&s=25 Stefan Rusterholz (apeiros)
on 2007-02-16 17:45
Yukihiro Matsumoto wrote:
> Hi,
>
> In message "Re: Oppinions on RCR for dup on immutable classes"
>     on Fri, 16 Feb 2007 08:55:12 +0900, "Phrogz" <gavin@refinery.com>
> writes:
>
> |That's a statement of fact, but doesn't explain *why* it's a problem,
> |or (important for an RCR) why it needs to be fixed in the core of the
> |language.
> |
> |What is the use case that is prevented by the problem? What does it
> |make inconvenient? Why should it be changed?
>
> Seconded.  It pretty trivial for us core developers to make dup for
> immutable objects to return themselves, but _I_ don't understand why
> it is needed.  I assume obj.object_id != obj.dup.object_id, and see no
> good reason enough to break the assumption.
>
>               matz.

That's why I have 2 suggestions. The issue arises when you don't know
what you dup.
Under the aspect that obj.object_id should always be ==
obj.dup.object_id the first suggestion
of removing dup from those classes would be more appropriate.
To me it seems inconsequential to implement a method with it only
raising an Exception.
That makes it impossible to check if your object doesn't actually
implement dup (e.g. via
respond_to?). To me it seems that it should either be an implementation
detail that
those classes can't really be duped (ie. return self) or expose that
transparently (not implement dup).
That of course is my personal oppinion and I'm posting this on the ML to
see if it is only me :)

My regards.
31e038e4e9330f6c75ccfd1fca8010ee?d=identicon&s=25 Gregory Brown (Guest)
on 2007-02-16 18:41
(Received via mailing list)
On 2/16/07, Stefan Rusterholz <apeiros@gmx.net> wrote:
> > |
> That's why I have 2 suggestions. The issue arises when you don't know
> those classes can't really be duped (ie. return self) or expose that
> transparently (not implement dup).

>> a = 3
=> 3
>> b = a.dup rescue a
=> 3
>> b
=> 3

What's so bad about that?
7b4707f974af261f71943e1f2046c9ee?d=identicon&s=25 SonOfLilit (Guest)
on 2007-02-16 18:48
(Received via mailing list)
On 2/16/07, Gregory Brown <gregory.t.brown@gmail.com> wrote:
>
>
When you use #dup not knowing about this complication, never dup a
Fixnum in
testing, but happen to dup one in production - e.g. in a library
released to
the public.


Ruby is always about principle-of-least-surprise and this behavior
really
surprised me when I first read about it non-list (I've stayed away from
object copies in MY code, because it all seems so hacky and arcane to
me...
Truns out it was a good idea)
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-02-16 19:43
(Received via mailing list)
On 2/16/07, Gregory Brown <gregory.t.brown@gmail.com> wrote:
> > > |language.
> >
> > detail that
> What's so bad about that?
>
>

I would ask the question: Why do you dup a?
The answer is, I presume, because I will modify the duplicate and  I
do not want to modify the original.
ok so let us follow our code

b= a.dup rescue a
...

b.mutating_method
what will happen now?

Cheers
Robert
852a62a28f1de229dc861ce903b07a60?d=identicon&s=25 Gavin Kistner (phrogz)
on 2007-02-16 19:50
(Received via mailing list)
From: SonOfLilit [mailto:sonoflilit@gmail.com]
Sent: Friday, February 16, 2007 10:48 AM
> Ruby is always about principle-of-least-surprise and this behavior
> really surprised me when I first read about it non-list (I've stayed
> away from object copies in MY code, because it all seems so hacky and
> arcane to me... Truns out it was a good idea)

Actually, Ruby is about the principle-of-least-surprise-for-matz.

I used to think POLS applied to everyone when I started with Ruby.
Many people, including Matz, pointed out that it's impossible to make
things unsurprising to everyone, because people will be surprised by
different things.

Just because something is surprising to you doesn't mean that it
should be changed in Ruby. You are advised (as was I) not to use POLS
as justification for why something should be changed.

...

Having said that, I personally would prefer for 3.dup to 'just work',
returning an object that is equivalent to the original. Just because
the new instance happens to be the same doesn't mean that it's bad -
as an immutable object, the only way to tell is via object_id, anyhow.
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2007-02-16 19:54
(Received via mailing list)
Hi --

On Sat, 17 Feb 2007, Phrogz wrote:

> Many people, including Matz, pointed out that it's impossible to make
> returning an object that is equivalent to the original. Just because
> the new instance happens to be the same doesn't mean that it's bad -
> as an immutable object, the only way to tell is via object_id, anyhow.

It doesn't mean it's bad, but it does mean that it isn't a duplicate
:-)  At least, I wouldn't think that dup is the right name for a
method that might actually return the receiver.


David
852a62a28f1de229dc861ce903b07a60?d=identicon&s=25 Gavin Kistner (phrogz)
on 2007-02-16 19:55
(Received via mailing list)
On Feb 16, 11:43 am, "Robert Dober" <robert.do...@gmail.com> wrote:
> I would ask the question: Why do you dup a?
> The answer is, I presume, because I will modify the duplicate and  I
> do not want to modify the original.
> ok so let us follow our code
>
> b= a.dup rescue a
> ..
>
> b.mutating_method
> what will happen now?

I'm not sure what your point is, Robert. Is it:

a) See, there's no point in duplicating an immutable object, since the
only reason to #dup is so you can mutate the instance later, and
anything you tried to do to mutate it would fail later on.

or is it

b) You should never ever write "a.dup rescue a" because it will give
you strange problems if a might refer to a mutable object that doesn't
respond to #dup.

?
852a62a28f1de229dc861ce903b07a60?d=identicon&s=25 Gavin Kistner (phrogz)
on 2007-02-16 20:16
(Received via mailing list)
On Feb 16, 11:53 am, dbl...@wobblini.net wrote:
> On Sat, 17 Feb 2007, Phrogz wrote:
> > ...
> > Having said that, I personally would prefer for 3.dup to 'just work',
> > returning an object that is equivalent to the original. Just because
> > the new instance happens to be the same doesn't mean that it's bad -
> > as an immutable object, the only way to tell is via object_id, anyhow.
>
> It doesn't mean it's bad, but it does mean that it isn't a duplicate
> :-)  At least, I wouldn't think that dup is the right name for a
> method that might actually return the receiver.

My perspective is:
If a duplicate of an immutable object is indistinguishable from the
original, then you would have no idea if #dup was returning an
internal duplicate or the same instance. And you wouldn't care (except
that you'd probably prefer it to conserve resources internally and
return the same instance).

The determining question for me, then, is:
How indistinguishable would two distinct instances of these immutable
objects be? The only case where code might break is if you had:
  b = a.dup
  h = { a.object_id => 1, b.object_id=> 2 }
and you were very unhappy if you ended up running over the key. I've
never personally used object_id for that purpose (or any other than
debugging), so I'm not sure how likely that is. I just use objects
themselves as hash keys, in which case equivalent instances already
behave the same (even of mutable objects!):

irb(main):001:0> a = []; b=a.dup
=> []
irb(main):002:0> p a.object_id, b.object_id
23327420
23327410
irb(main):003:0> h = {a=>1, b=>2}
=> {[]=>2}

irb(main):013:0> a,b = 1234567890,1234567890
=> [1234567890, 1234567890]
irb(main):014:0> p a.class, a.object_id, b.class, b.object_id
Bignum
23346300
Bignum
23346270
=> nil
irb(main):015:0> h = {a=>1,b=>2}
=> {1234567890=>2}
E7559e558ececa67c40f452483b9ac8c?d=identicon&s=25 Gary Wright (Guest)
on 2007-02-16 20:25
(Received via mailing list)
On Feb 16, 2007, at 1:50 PM, Phrogz wrote:
> Having said that, I personally would prefer for 3.dup to 'just work',
> returning an object that is equivalent to the original. Just because
> the new instance happens to be the same doesn't mean that it's bad -
> as an immutable object, the only way to tell is via object_id, anyhow.

I've come across this situation when writing generic code to do a
'deep copy'.  Instead of changing the semantics of #dup, why not have
some other method that means 'make a copy if you can but if the object
has immutable semantics then return a reference to self'.

As for a name for such a method, how about Kernel#another ?

I'm not sure how #dup, #clone, and #another should be related.  Perhaps
#another should use #clone instead of #dup?  Maybe there should be
another
version of #another that uses clone semantics?

Gary Wright
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2007-02-16 20:32
(Received via mailing list)
Hi --

On Sat, 17 Feb 2007, Phrogz wrote:

>> method that might actually return the receiver.
> objects be? The only case where code might break is if you had:
> irb(main):002:0> p a.object_id, b.object_id
> Bignum
> 23346270
> => nil
> irb(main):015:0> h = {a=>1,b=>2}
> => {1234567890=>2}

You could conceivably have a case where an object can't be dup'd, but
is mutable, like a singleton class.  If dup returns self, then you
could end up changing the object when you didn't want to.  It's
probably not an everyday problem... but I still don't like the idea of
having to remember that "dup" means "dup or self".


David
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2007-02-16 20:34
(Received via mailing list)
Hi --

On Sat, 17 Feb 2007, Gary Wright wrote:

> has immutable semantics then return a reference to self'.
>
> As for a name for such a method, how about Kernel#another ?

But self isn't other than self.

> I'm not sure how #dup, #clone, and #another should be related.  Perhaps
> #another should use #clone instead of #dup?  Maybe there should be another
> version of #another that uses clone semantics?

#another_another? :-)


David
852a62a28f1de229dc861ce903b07a60?d=identicon&s=25 Gavin Kistner (phrogz)
on 2007-02-16 20:51
(Received via mailing list)
On Feb 16, 12:30 pm, dbl...@wobblini.net wrote:
> You could conceivably have a case where an object can't be dup'd, but
> is mutable, like a singleton class.  If dup returns self, then you
> could end up changing the object when you didn't want to.  It's
> probably not an everyday problem... but I still don't like the idea of
> having to remember that "dup" means "dup or self".

Yes, but that would only be a problem if you did:
  class Object
    alias old_dup dup
    def dup
      self.old_dup rescue self
    end
  end

I would certainly not like that, either.

The OPs proposal, however, was to modify the behavior only for a
particular set of built-in immutable objects:
[NilClass, FalseClass, TrueClass, Fixnum, Symbol]

(Though, if you 'fix' Fixnum like this, you'll need to 'fix' Bignum
and Float and others as well to support duping.)
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-02-16 20:54
(Received via mailing list)
On 2/16/07, Phrogz <gavin@refinery.com> wrote:
> >
>
> I'm not sure what your point is, Robert. Is it:
>
> a) See, there's no point in duplicating an immutable object, since the
> only reason to #dup is so you can mutate the instance later, and
> anything you tried to do to mutate it would fail later on.
Exactly
but I did not say that it was bad an idiom, it is not an idiom IMHO as
useful as it might look first.
AAMOF I was about to say first: Hey this idiom is great so no RCR is
needed.
And then I thought... -  hey that can happen ;)
and I realized that these are strange cases to call dup to protect an
object from mutation and I want it that for immutable objects on the
fly. I am sure there are usecases, but view.

My conclusion was this is not an idiom worth a CR at all.

>
> or is it
>
> b) You should never ever write "a.dup rescue a" because it will give
> you strange problems if a might refer to a mutable object that doesn't
> respond to #dup.
Neve say never ;) but when you write
a.dup rescue a
you should be aware of that potential danger

a.dup
will not really alert the user enough of that, I feel.
>
> ?
>
Strangely enough I fail to see the difference between a) and b)

Cheers
Robert
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2007-02-16 20:57
(Received via mailing list)
On Sat, 17 Feb 2007 dblack@wobblini.net wrote:

> You could conceivably have a case where an object can't be dup'd, but is
> mutable, like a singleton class.  If dup returns self, then you could end up
> changing the object when you didn't want to.  It's probably not an everyday
> problem... but I still don't like the idea of having to remember that "dup"
> means "dup or self".


you already do though?



harp:~ > cat a.rb
#
# crappy
#
   h = { :point => 'we already have' }

   h2 = h.dup

   h2[:point] << ' that problem'

   p h[:point]
#
# crappy
#
   h = { :point => 'we already have' }

   h2 = h.clone

   h2[:point] << ' that problem'

   p h[:point]
#
# sledge hammer
#
   h = { :point => 'an imperfect solution' }

   mcp = lambda{|obj| Marshal.load(Marshal.dump(obj))}

   h2 = mcp[ h ]

   h2[:point] << ' is to use marshal'

   p h[:point]


harp:~ > ruby a.rb
"we already have that problem"
"we already have that problem"
"an imperfect solution"


-a
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2007-02-16 21:06
(Received via mailing list)
Hi --

On Sat, 17 Feb 2007, ara.t.howard@noaa.gov wrote:

> you already do though?
>
>  h2[:point] << ' that problem'
>
>  h2[:point] << ' is to use marshal'
>
>  p h[:point]
>
>
> harp:~ > ruby a.rb
> "we already have that problem"
> "we already have that problem"
> "an imperfect solution"

I don't consider returning a shallow copy the same as returning self.
It's not the same object as the receiver of the "dup" message.


David
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2007-02-16 21:11
(Received via mailing list)
On Sat, 17 Feb 2007 dblack@wobblini.net wrote:

>
> I don't consider returning a shallow copy the same as returning self.
> It's not the same object as the receiver of the "dup" message.
>

you may not.  neither do i.  nevetheless it quite true that one must
understand __completey__ the rhs in

   d = obj.dup

in order to use d effectively.


-a
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2007-02-16 21:16
(Received via mailing list)
Hi --

On Sat, 17 Feb 2007, ara.t.howard@noaa.gov wrote:

>  d = obj.dup
>
> in order to use d effectively.

I'm definitely not lobbying against understanding things :-)


David
31e038e4e9330f6c75ccfd1fca8010ee?d=identicon&s=25 Gregory Brown (Guest)
on 2007-02-16 23:29
(Received via mailing list)
On 2/16/07, Robert Dober <robert.dober@gmail.com> wrote:
> On 2/16/07, Phrogz <gavin@refinery.com> wrote:

> > b) You should never ever write "a.dup rescue a" because it will give
> > you strange problems if a might refer to a mutable object that doesn't
> > respond to #dup.
> Neve say never ;) but when you write
> a.dup rescue a
> you should be aware of that potential danger

Right.  My only point was that this solved what the OP asked for
without being hard.
It just seems like that solution is no better or worse than changing
the behaviour of dup, except for the fact that it puts the burden of
bad design into the programmer's hands, and not that of the
programming language :)
852a62a28f1de229dc861ce903b07a60?d=identicon&s=25 Gavin Kistner (phrogz)
on 2007-02-16 23:40
(Received via mailing list)
On Feb 16, 3:28 pm, "Gregory Brown" <gregory.t.br...@gmail.com> wrote:
> Right.  My only point was that this solved what the OP asked for
> without being hard.
> It just seems like that solution is no better or worse than changing
> the behaviour of dup, except for the fact that it puts the burden of
> bad design into the programmer's hands, and not that of the
> programming language :)

IF the proposed implementation were to do what you suggested - rescue
every dup error by returning self - then I would agree that it's a bad
design feature to put into the language.

I personally believe that returning self for symbols, fixnums, true,
false, and nil is not bad or dangerous in any way. Can you provide a
single example (even if contrived) where this could produce an
unintended result? I can only come up with one myself, and it's too
contrived for me to consider it a danger.
31e038e4e9330f6c75ccfd1fca8010ee?d=identicon&s=25 Gregory Brown (Guest)
on 2007-02-17 00:47
(Received via mailing list)
On 2/16/07, Phrogz <gavin@refinery.com> wrote:
> >
>
> I personally believe that returning self for symbols, fixnums, true,
> false, and nil is not bad or dangerous in any way. Can you provide a
> single example (even if contrived) where this could produce an
> unintended result? I can only come up with one myself, and it's too
> contrived for me to consider it a danger.

the only things I can think of involve singleton methods

>> def nil.foo
>>   "hi there"
>> end
=> nil
>> nil.foo
=> "hi there"
>> b = nil.dup
TypeError: can't dup NilClass
        from (irb):13:in `dup'
        from (irb):13
>> def b.bar; "confusing?"; end

Imagine no error was thrown by that dup.

bar would be defined both on the duped (really not duped at all) nil
in your b variable, and on nil itself.

This of course is contrived, but it would be surprising behaviour.  (I
think)
852a62a28f1de229dc861ce903b07a60?d=identicon&s=25 Gavin Kistner (phrogz)
on 2007-02-17 07:45
(Received via mailing list)
On Feb 16, 4:47 pm, "Gregory Brown" <gregory.t.br...@gmail.com> wrote:
> >>   "hi there"
> >> def b.bar; "confusing?"; end
>
> Imagine no error was thrown by that dup.
>
> bar would be defined both on the duped (really not duped at all) nil
> in your b variable, and on nil itself.
>
> This of course is contrived, but it would be surprising behaviour.  (I think)

A very good case. Enough so that I change my vote from "change dup" to
"leave things as they are".
Cf7cd97cdc8ed7d4ae92965b24f0dfad?d=identicon&s=25 Stefan Rusterholz (apeiros)
on 2007-02-17 08:47
Gregory Brown wrote:
> On 2/16/07, Stefan Rusterholz <apeiros@gmx.net> wrote:
>> > |
>> That's why I have 2 suggestions. The issue arises when you don't know
>> those classes can't really be duped (ie. return self) or expose that
>> transparently (not implement dup).
>
>>> a = 3
> => 3
>>> b = a.dup rescue a
> => 3
>>> b
> => 3
>
> What's so bad about that?

As I said, I consider it a minor glitch. Of course you can work around
the problem, but a workaround is still only a workaround. IMHO the
"correct" way to do what you do above would be:

b = a.respond_to?(:dup) ? a.dup : a

If you have concerns about that beeing not as fast as rescuing your code
would still work (the raised exception would just be different).
Since that is my oppinion I posted this to the ML to see what other
oppinions about that are.
Besides, your above code assumes that the only reason a dup fails is due
to the singleton-immutables, what if dup fails due to another reason?
With your above code you'll have a happy time tracking the bug as a
potential exception will never be raised.

My regards
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2007-02-17 14:18
(Received via mailing list)
Hi,

In message "Re: Oppinions on RCR for dup on immutable classes"
    on Sat, 17 Feb 2007 01:45:17 +0900, Stefan Rusterholz
<apeiros@gmx.net> writes:

|> Seconded.  It pretty trivial for us core developers to make dup for
|> immutable objects to return themselves, but _I_ don't understand why
|> it is needed.  I assume obj.object_id != obj.dup.object_id, and see no
|> good reason enough to break the assumption.

|That's why I have 2 suggestions. The issue arises when you don't know
|what you dup.

But your other suggestion was just removing dup altogether, right?  In
that case, I see no fundamental difference from the current behavior
that raises TypeError with message "can't dup" rather than
NoMethodError.  Exception handling is your friend.

              matz.
Cf7cd97cdc8ed7d4ae92965b24f0dfad?d=identicon&s=25 Stefan Rusterholz (apeiros)
on 2007-02-17 14:51
Yukihiro Matsumoto wrote:
> Hi,
>
> In message "Re: Oppinions on RCR for dup on immutable classes"
>     on Sat, 17 Feb 2007 01:45:17 +0900, Stefan Rusterholz
> <apeiros@gmx.net> writes:
>
> |> Seconded.  It pretty trivial for us core developers to make dup for
> |> immutable objects to return themselves, but _I_ don't understand why
> |> it is needed.  I assume obj.object_id != obj.dup.object_id, and see no
> |> good reason enough to break the assumption.
>
> |That's why I have 2 suggestions. The issue arises when you don't know
> |what you dup.
>
> But your other suggestion was just removing dup altogether, right?  In
> that case, I see no fundamental difference from the current behavior
> that raises TypeError with message "can't dup" rather than
> NoMethodError.  Exception handling is your friend.
>
>               matz.

With current implementation, the only way to figure if an object can be
dup'ed is by dup it and catch the exception. I don't know how imperative
duck-typing is for ruby, but this way actively prohibits it.
The method signature of those classes suggests it can be dup'ed, but
"hidden" in the code it actually shows that it isn't. That's in my
oppinion intransparent.
As said before, the issue can be worked around (as you say e.g. via
exception handling), but following your argument, my question would be:
why implement a method that can't be executed?
I'll restate again, that I consider it a minor issue. But I thought with
ruby2 and the cleanup of the APIs I thought it might be worth pointing.

My regards
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2007-02-17 15:21
(Received via mailing list)
Hi,

In message "Re: Oppinions on RCR for dup on immutable classes"
    on Sat, 17 Feb 2007 22:51:06 +0900, Stefan Rusterholz
<apeiros@gmx.net> writes:

|With current implementation, the only way to figure if an object can be
|dup'ed is by dup it and catch the exception. I don't know how imperative
|duck-typing is for ruby, but this way actively prohibits it.

As far as I understand, DuckTyping is not something based on method
existence, but something letting them raise error without explicit
type checking.

|As said before, the issue can be worked around (as you say e.g. via
|exception handling), but following your argument, my question would be:
|why implement a method that can't be executed?

We haven't implemented a method that can't be executed.  Object#dup
just fails if the object is not able to be duped.  Am I missing
something?

              matz.
31e038e4e9330f6c75ccfd1fca8010ee?d=identicon&s=25 Gregory Brown (Guest)
on 2007-02-17 15:58
(Received via mailing list)
On 2/17/07, Stefan Rusterholz <apeiros@gmx.net> wrote:

> As I said, I consider it a minor glitch. Of course you can work around
> the problem, but a workaround is still only a workaround. IMHO the
> "correct" way to do what you do above would be:
>
> b = a.respond_to?(:dup) ? a.dup : a

You're right, this is a better way.   I don't consider it a work
around.  I consider it to be accounting for a language implementation
detail.  (In that some objects cannot inherently be dup'ed)

> If you have concerns about that beeing not as fast as rescuing your code
> would still work (the raised exception would just be different).
> Since that is my oppinion I posted this to the ML to see what other
> oppinions about that are.
> Besides, your above code assumes that the only reason a dup fails is due
> to the singleton-immutables, what if dup fails due to another reason?
> With your above code you'll have a happy time tracking the bug as a
> potential exception will never be raised.

If I wrote that code, I'd assume it was behaving as I intended, and be
sure to have tests to show it, but truthfully, the code you mentioned
is better.

It's valid to consider that if you are dup'ing objects that shouldn't
be duped 'by accident', then perhaps something has gone wrong in your
program design.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2007-02-17 16:05
(Received via mailing list)
On Sat, 17 Feb 2007, Stefan Rusterholz wrote:

>
> With current implementation, the only way to figure if an object can be
> dup'ed is by dup it and catch the exception. I don't know how imperative
> duck-typing is for ruby, but this way actively prohibits it.  The method
> signature of those classes suggests it can be dup'ed, but "hidden" in the
> code it actually shows that it isn't. That's in my oppinion intransparent.
> As said before, the issue can be worked around (as you say e.g. via
> exception handling), but following your argument, my question would be: why
> implement a method that can't be executed?

because, in ruby, all methods can be changed all the time:

   class C
     def dup() raise "now you can't" end
   end

   c = C.new

   c.dup rescue nil

   class << c
     def dup() raise "now you can" end
   end

   c.dup

just because an object responded to a message one time, at compile time,
or
whatever - doesn't mean it will later.  this is the dynamic in 'dynamic
languages.'

note that being able to dump singleton classes doesn't change this one
bit.

regards.


-a
F690ec04b0501b74b033fc64ff4f682b?d=identicon&s=25 Dean Wampler (Guest)
on 2007-02-17 16:15
(Received via mailing list)
On 2/17/07, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:
> existence, but something letting them raise error without explicit
>                                                         matz.
For me, this does break the POLS, because it breaks the Liskov
Substitution Principle (loosely, "an object of a derived type can be
substituted for an object of a base type", for those of you who
haven't heard of it...). LSP is essentially the underpinnings of
Bertrand Meyer's "Design by Contract".

If I'm iterating through a collection of objects and all of them
respond_to? a method, yet an exception is thrown in some cases, that's
surprising ;)  The deep-copy scenario is a good one. In this case, it
would be nice to have a succinct way of copying the object graph
without having to worry about some dup methods "not working". Perhaps
the "another" method suggestion would work. Perhaps thinking through
all the scenarios of why you would dup an object would suggest
refinements to its behavior. Off hand, I'm wondering if it would be so
bad for an immutable object, like a Fixnum, to allow a.object_id? ==
a.dup.object_id?.

I'm probably missing some important points, as I don't know the
intricasies of Ruby as well as many of you do. This is a typical
dilemma with rich base classes and modules. Occasionally, the rich
"contract" can't be satisfied transparently by all derivatives. Maybe
that's just the price we have to pay for being rich ;)

Dean Wampler
http://www.objectmentor.com
http://www.aspectprogramming.com
http://www.contract4j.org
31e038e4e9330f6c75ccfd1fca8010ee?d=identicon&s=25 Gregory Brown (Guest)
on 2007-02-17 16:20
(Received via mailing list)
On 2/17/07, Dean Wampler <deanwampler@gmail.com> wrote:

> I'm probably missing some important points, as I don't know the
> intricasies of Ruby as well as many of you do.

POLS when applied to Ruby refers to Matz's surprise.  In this thread
and others, we need to remind people of that.   Ruby is easy to
change, for your own needs.  Feel free :)
Cf7cd97cdc8ed7d4ae92965b24f0dfad?d=identicon&s=25 Stefan Rusterholz (apeiros)
on 2007-02-17 16:33
unknown wrote:
> because, in ruby, all methods can be changed all the time:
>
>    class C
>      def dup() raise "now you can't" end
>    end
>
>    c = C.new
>
>    c.dup rescue nil
>
>    class << c
>      def dup() raise "now you can" end
>    end
>
>    c.dup
>
> just because an object responded to a message one time, at compile time,
> or
> whatever - doesn't mean it will later.  this is the dynamic in 'dynamic
> languages.'
>
> note that being able to dump singleton classes doesn't change this one
> bit.
>
> regards.
>
>
> -a

Care to explain why you chose defining a method with the sole purpose of
raising an exception over removing the method instead?

My regards
Cf7cd97cdc8ed7d4ae92965b24f0dfad?d=identicon&s=25 Stefan Rusterholz (apeiros)
on 2007-02-17 16:37
Gregory Brown wrote:
> If I wrote that code, I'd assume it was behaving as I intended, and be
> sure to have tests to show it, but truthfully, the code you mentioned
> is better.
>
> It's valid to consider that if you are dup'ing objects that shouldn't
> be duped 'by accident', then perhaps something has gone wrong in your
> program design.

My issue is that I can't test that. I can only try and catch the
exception. With dup that's not too terrible as it doesn't have
side-effects. Still in my oppinion having to run code to see what
happens is not a clean behaviour.

My regards
31e038e4e9330f6c75ccfd1fca8010ee?d=identicon&s=25 Gregory Brown (Guest)
on 2007-02-17 16:49
(Received via mailing list)
On 2/17/07, Stefan Rusterholz <apeiros@gmx.net> wrote:

> My issue is that I can't test that. I can only try and catch the
> exception. With dup that's not too terrible as it doesn't have
> side-effects. Still in my oppinion having to run code to see what
> happens is not a clean behaviour.

Oh, good point.

>> 1.respond_to?(:dup)
=> 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.

>> class Fixnum
>>   undef :dup
>> end
=> nil
>> 2.dup
NoMethodError: undefined method `dup' for 2:Fixnum


BTW, Matz, the only difference I suppose is that by having a
NoMethodError, we could make use of respond_to? as a check, but I
don't know if I think it's such a big deal that I'd be in support of a
RCR.
Cf7cd97cdc8ed7d4ae92965b24f0dfad?d=identicon&s=25 Stefan Rusterholz (apeiros)
on 2007-02-17 16:54
Yukihiro Matsumoto wrote:
> As far as I understand, DuckTyping is not something based on method
> existence, but something letting them raise error without explicit
> type checking.

Hm, we probably have a different understanding of DuckTyping then.

> We haven't implemented a method that can't be executed.  Object#dup
> just fails if the object is not able to be duped.  Am I missing
> something?
>
>               matz.

I'll try to explain it differently, depict my issue. Say you go to a
restaurant, take a look at the card and see "Spagetthi". You order
Spagetthi but the waiter just tells you "Oh, we don't serve Spagetthi
here.". You'd naturally ask "Why put it on the card then if you don't
serve it at all?"

My regards
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2007-02-17 17:19
(Received via mailing list)
Hi,

In message "Re: Oppinions on RCR for dup on immutable classes"
    on Sun, 18 Feb 2007 00:54:42 +0900, Stefan Rusterholz
<apeiros@gmx.net> writes:

|Hm, we probably have a different understanding of DuckTyping then.

Perhaps.

|> We haven't implemented a method that can't be executed.  Object#dup
|> just fails if the object is not able to be duped.  Am I missing
|> something?

|I'll try to explain it differently, depict my issue. Say you go to a
|restaurant, take a look at the card and see "Spagetthi". You order
|Spagetthi but the waiter just tells you "Oh, we don't serve Spagetthi
|here.". You'd naturally ask "Why put it on the card then if you don't
|serve it at all?"

I imagine the waiter telling you "Oh, we don't serve Spaghetti
_today_".

              matz.
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-02-17 17:22
(Received via mailing list)
On 2/17/07, Dean Wampler <deanwampler@gmail.com> wrote:
> > As far as I understand, DuckTyping is not something based on method
> >
> >                                                         matz.
>
> For me, this does break the POLS, because it breaks the Liskov
> Substitution Principle
you are opening a can of worms (or ducks if you prefer).

I would say that LSP does not apply here simply because in Ruby we do
not have that kind of contract.
In order to apply LSP we need to say at at a point hey here we have an
object of class Base.(let the gods forgive me that I use Java)
void aMethod(final Base b){
   ....
}
and we expect this to work whenever we call aMethod with an object
that is a Base.
Anyway the compiler would not really allow otherwise.

SubClass sc;  // subclassing Base od course
aMethod( sc ); // this is expected to work (from the type POV).

Such things just do not exist in Ruby, I believe that Ruby has
explained something to me:

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


 (loosely, "an object of a derived type can be
> substituted for an object of a base type", for those of you who
> haven't heard of it...). LSP is essentially the underpinnings of
> Bertrand Meyer's "Design by Contract".
>
> If I'm iterating through a collection of objects and all of them
> respond_to? a method, yet an exception is thrown in some cases, that's
> surprising ;)

Do not let *your* code surprise *you*. If it does than it is not the
language's fault.
But I have seen the smiley ;)

>The deep-copy scenario is a good one. In this case, it
> would be nice to have a succinct way of copying the object graph
> without having to worry about some dup methods "not working".

Meaning not worrying about the semantics of your program ???
But you still have a good use case below, not good enough for a RCR but
good. --> see my last point too please.

> "contract" can't be satisfied transparently by all derivatives. Maybe
> that's just the price we have to pay for being rich ;)

Instead of advocating for a RCR especially in the present scenario which
is:
"Well that might be bad sometimes and goos sometimes, not really worth a
CR"
you might just create your own little toolbox.
class Integer ... def dup   etc.

Advocating is a good thing but it is not the only one.
After some months of using your toolbox you might still want the CR or
maybe throw it away, who knows?

Cheers
Robert

P.S.
I am against the CR but the discussion is a great one! Thumbs up!
R.
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2007-02-17 17:24
(Received via mailing list)
Hi,

In message "Re: Oppinions on RCR for dup on immutable classes"
    on Sun, 18 Feb 2007 00:15:20 +0900, "Dean Wampler"
<deanwampler@gmail.com> writes:

|For me, this does break the POLS, because it breaks the Liskov
|Substitution Principle (loosely, "an object of a derived type can be
|substituted for an object of a base type", for those of you who
|haven't heard of it...). LSP is essentially the underpinnings of
|Bertrand Meyer's "Design by Contract".

Please no POLS here.  Considering whom you're trying to persuade, it's
no use.

As for LSP, if Object class has dup method and Fixnum the subclass of
Object does not have dup, doesn't it break the LSP?  Fixnum no longer
has all the methods that Object has.

              matz.
Cf7cd97cdc8ed7d4ae92965b24f0dfad?d=identicon&s=25 Stefan Rusterholz (apeiros)
on 2007-02-17 17:37
Yukihiro Matsumoto wrote:
> |I'll try to explain it differently, depict my issue. Say you go to a
> |restaurant, take a look at the card and see "Spagetthi". You order
> |Spagetthi but the waiter just tells you "Oh, we don't serve Spagetthi
> |here.". You'd naturally ask "Why put it on the card then if you don't
> |serve it at all?"
>
> I imagine the waiter telling you "Oh, we don't serve Spaghetti
> _today_".
>
>               matz.

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

My regards
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2007-02-17 17:42
(Received via mailing list)
On Sun, 18 Feb 2007, Stefan Rusterholz wrote:

> Care to explain why you chose defining a method with the sole purpose of
> raising an exception over removing the method instead?

yes - for illustration  ;-)

a simpler example

   harp:~ > cat a.rb
   require 'singleton'

   a = Object.new.instance_eval{ @x = 42 and self }
   p a.dup

   a.instance_eval{ class << self; include Singleton; end }
   p a.dup


   harp:~ > ruby a.rb
   #<Object:0xb75cbb44 @x=42>
   /home/ahoward//lib/ruby/1.8/singleton.rb:71:in `dup': can't dup
instance of singleton Object (TypeError)
           from a.rb:7


this is a side effect of strong dynamic type systems: the
interpreter/compiler
cannot know until runtime if a methods signature makes sense becaues
there are
an infinite variety of ways the semantics of a msg sent to an object
might
change betweent two transmissions to the same object.  if you don't like
this
there are two choices:

   - use language with a strong static type system.  this rules out
python,
     java, c++, c, perl, lisp, and smalltalk

   - dispair

regards.

-a
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2007-02-17 17:43
(Received via mailing list)
On Sun, 18 Feb 2007, Stefan Rusterholz wrote:

>
> My issue is that I can't test that. I can only try and catch the exception.
> With dup that's not too terrible as it doesn't have side-effects. Still in
> my oppinion having to run code to see what happens is not a clean behaviour.
>

you should check out haskell - it's one of only a few languages that can
provide this feature.

-a
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2007-02-17 17:46
(Received via mailing list)
On Sun, 18 Feb 2007, Stefan Rusterholz wrote:

>
> I'll try to explain it differently, depict my issue. Say you go to a
> restaurant, take a look at the card and see "Spagetthi". You order Spagetthi
> but the waiter just tells you "Oh, we don't serve Spagetthi here.". You'd
> naturally ask "Why put it on the card then if you don't serve it at all?"
>

because we serve it sometimes.  in addition, most of our employees know
how to
make it at any time.  we might not have it today though.  our we might,
but
we're out of meatballs.

-a
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2007-02-17 18:00
(Received via mailing list)
Hi,

In message "Re: Oppinions on RCR for dup on immutable classes"
    on Sun, 18 Feb 2007 01:37:19 +0900, Stefan Rusterholz
<apeiros@gmx.net> writes:

|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.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2007-02-17 18:07
(Received via mailing list)
On Sun, 18 Feb 2007, Stefan Rusterholz wrote:

>>               matz.
>
> 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 :)

not really, you just have to learn how to cook! ;-)

   harp:~ > cat a.rb
   module DupSelf
     def dup() self end
   end

   nil.extend DupSelf

   p nil.dup

   harp:~ > ruby a.rb
   nil

regards.

-a
31e038e4e9330f6c75ccfd1fca8010ee?d=identicon&s=25 Gregory Brown (Guest)
on 2007-02-17 18:09
(Received via mailing list)
On 2/17/07, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:

> 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.
Cf7cd97cdc8ed7d4ae92965b24f0dfad?d=identicon&s=25 Stefan Rusterholz (apeiros)
on 2007-02-17 18:50
unknown wrote:
> On Sun, 18 Feb 2007, Stefan Rusterholz wrote:
>
>> Care to explain why you chose defining a method with the sole purpose of
>> raising an exception over removing the method instead?
>
> 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
Cf7cd97cdc8ed7d4ae92965b24f0dfad?d=identicon&s=25 Stefan Rusterholz (apeiros)
on 2007-02-17 18:54
Yukihiro Matsumoto wrote:
> Hi,
>
> In message "Re: Oppinions on RCR for dup on immutable classes"
>     on Sun, 18 Feb 2007 01:37:19 +0900, Stefan Rusterholz
> <apeiros@gmx.net> writes:
>
> |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
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2007-02-17 19:30
(Received via mailing list)
Hi --

On Sun, 18 Feb 2007, Stefan Rusterholz wrote:

>>
> 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
7b4707f974af261f71943e1f2046c9ee?d=identicon&s=25 SonOfLilit (Guest)
on 2007-02-17 19:33
(Received via mailing list)
On 2/17/07, Gregory Brown <gregory.t.brown@gmail.com> wrote:
> => true
> >> 2.dup
> 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?
31e038e4e9330f6c75ccfd1fca8010ee?d=identicon&s=25 Gregory Brown (Guest)
on 2007-02-17 19:39
(Received via mailing list)
On 2/17/07, SonOfLilit <sonoflilit@gmail.com> wrote:

> 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? :)  )
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2007-02-17 19:43
(Received via mailing list)
On Sun, 18 Feb 2007, Stefan Rusterholz wrote:

> unknown wrote:
>> On Sun, 18 Feb 2007, Stefan Rusterholz wrote:
>>
>>> Care to explain why you chose defining a method with the sole purpose of
>>> raising an exception over removing the method instead?
>>
>> yes - for illustration  ;-)
>
> 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.

>
>> this is a side effect of strong dynamic type systems
>
> 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
Cf7cd97cdc8ed7d4ae92965b24f0dfad?d=identicon&s=25 Stefan Rusterholz (apeiros)
on 2007-02-17 20:30
unknown wrote:
> 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
31e038e4e9330f6c75ccfd1fca8010ee?d=identicon&s=25 Gregory Brown (Guest)
on 2007-02-17 20:35
(Received via mailing list)
On 2/17/07, Stefan Rusterholz <apeiros@gmx.net> wrote:
> >      def 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
Cf7cd97cdc8ed7d4ae92965b24f0dfad?d=identicon&s=25 Stefan Rusterholz (apeiros)
on 2007-02-17 20:43
Gregory Brown wrote:
> 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.
F690ec04b0501b74b033fc64ff4f682b?d=identicon&s=25 Dean Wampler (Guest)
on 2007-02-17 21:10
(Received via mailing list)
> ...
>
> 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.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2007-02-17 21:18
(Received via mailing list)
On Sun, 18 Feb 2007, Dean Wampler wrote:

>
> 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
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2007-02-17 21:28
(Received via mailing list)
On Sun, 18 Feb 2007 Ara.T.Howard@noaa.gov wrote:

>
> responds to it.
... or even if it doesn't:  method_missing

-a
31e038e4e9330f6c75ccfd1fca8010ee?d=identicon&s=25 Gregory Brown (Guest)
on 2007-02-17 21:53
(Received via mailing list)
On 2/17/07, Stefan Rusterholz <apeiros@gmx.net> wrote:
> "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

>> 3.dup
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.
31e038e4e9330f6c75ccfd1fca8010ee?d=identicon&s=25 Gregory Brown (Guest)
on 2007-02-17 22:06
(Received via mailing list)
On 2/17/07, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:
>  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"
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2007-02-17 22:17
(Received via mailing list)
On Sun, 18 Feb 2007, Gregory Brown wrote:

>>>     dup
> => "foo"
>

same semantics - but nice and clean.

-a
Ea24c17719a975fb38c107a60f4b3802?d=identicon&s=25 Vincent Fourmond (Guest)
on 2007-02-17 23:24
(Received via mailing list)
ara.t.howard@noaa.gov wrote:
>> => nil
>>>> 3.dup?
>> => false
>>>> 3.dup? || 3
>> => 3
>>>> "foo".dup?
>> => "foo"
>>
>
> same semantics - but nice and clean.

+1
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2007-02-17 23:37
(Received via mailing list)
Hi --

On Sun, 18 Feb 2007, Gregory Brown wrote:

>>>     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
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-02-17 23:57
(Received via mailing list)
On 2/17/07, Dean Wampler <deanwampler@gmail.com> wrote:
> "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
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2007-02-18 00:17
(Received via mailing list)
Hi --

On Sun, 18 Feb 2007, Robert Dober wrote:

> On 2/17/07, Dean Wampler <deanwampler@gmail.com> wrote:
>>
>> 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?

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
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-02-18 00:30
(Received via mailing list)
On 2/17/07, dblack@wobblini.net <dblack@wobblini.net> wrote:
> > (euphemistically)
> gracious to explain why not (in the exception message).
> 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.
Very well put David. I can only agree, it is better behavior.
Sorry Ara if I missed that post of yours this thread is a little bit
complex.
R.
31e038e4e9330f6c75ccfd1fca8010ee?d=identicon&s=25 Gregory Brown (Guest)
on 2007-02-18 01:45
(Received via mailing list)
On 2/17/07, dblack@wobblini.net <dblack@wobblini.net> wrote:

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

Let me just play devils advocate for a sec.

>> 4.nonzero?
=> 4
>> 0.nonzero?
=> nil

I just think that dup?  is a good compromise for third party hacking.
Not an RCR.

That having been said, I've not used nonzero? and I too am expecting
booleans from things that end in ?, but that was the best thing I
could come up with  ;)
B73dde621deaf42324793d8517b0b78c?d=identicon&s=25 Greg Hurrell (Guest)
on 2007-02-18 12:36
(Received via mailing list)
I personally would like to see immutable objects like Nil and Fixnum
return self if sent a dup message.

The problem with the currently model is that it makes it difficult for
the programmer to make a distinction between "by copy" ("by value")
and "by reference". The most obvious example to look at is instance
variables.

There are some cases where you want your instance variables to be set
"by reference"; that is, where you are interested in a particular,
specific object and want to keep track of it, including changes in its
value, over time. Most often the kind of object you want to pass in by
reference is a high-level object that encapsulates some kind of
complex state and behaviour.

There are also cases where you want your instance variables to be set
"by copy"; that is, where you are not concerned about the identity of
an object and only care about the value of the object at the time you
assign it to a variable. Most commonly the kinds of objects you'll
want to pass by copy are simple, primitive objects, usually numbers,
strings and values like nil.

The trouble is not that Ruby passes everything "by reference" by
default, but that Ruby makes it hard for you to pass "by copy" ("by
value") when you want to. Imagine an instance variable for which
you've defined an accessor using "attr_accessor". By default this will
pass "by reference".

If you want to pass "by copy" you have to manually write an accessor.
But if you write your accessor like this:

def my_var=(value)
  @my_var = value.dup
end

You'll get exceptions whenever you pass nil (a very common case, I
would imagine). Change it to this:

def my_var=(value)
  @my_var = (value.respond_to? :dup ? value.dup : value)
end

This works for nil, but it's not as readable because of the extra
punctuation. Try passing in a Fixnum though; you'll get an exception
because Fixnum claims to respond to "dup" but complains when you
actually send the message (pretty surprising). So you have to do this:

def my_var=(value)
  @my_var = value.dup rescue value
end

To me this seems like an awful lot of work every time you want an
instance variable to be "by copy" ("by value") instead of "by
reference". Yes, you'll might have problems here if you pass in a
singleton-but-mutable object, but I assume that if you know enough
about what you're doing to specifically want things to be passed in
"by copy" ("by value") then you also know exactly what will happen
when try passing in a singleton-but-mutable object.

As a programmer coming from Objective-C one of the current behaviour
was one the most annoying things about Ruby. Now I just write my
accessors using "rescue" whenever I want "by copy" behaviour. I
probably wouldn't have had to adopt this habit if classes like Nil and
Fixnum just returned self in response to the "dup" message. This is
the orthodox behaviour in Objective-C; in fact, even singleton-but-
mutable classes normally just return self if sent the "copy" message.

An even more elegant solution, however, would be to extend
"attr_accessor" and friends to allow the programmer to specify if
attributes should be set "by copy" or "by reference". This is exactly
what the new Obejctive-C 2.0 provides. In those cases where you want
to override the default behaviour you would do a
"attr_accessor_bycopy :my_var" and Ruby would do the right thing. Of
course, there is nothing stopping me from writing my very own
"attr_accessor_bycopy" method, but it would be nice if it were a
feature of Ruby itself.

Cheers,
Greg
7b4707f974af261f71943e1f2046c9ee?d=identicon&s=25 SonOfLilit (Guest)
on 2007-02-18 13:17
(Received via mailing list)
Say, why not just define Object#mutable? and solve the issue of not
knowing if dup is possible or not?

Sure, it only works to tell you about one possible reason it's not,
but it seems like a good workaround, far better than, say, duping just
to check.

Aur Saraf
617b624fa01db9f6440439f3740b35e9?d=identicon&s=25 Marcello Barnaba (Guest)
on 2007-02-18 13:56
(Received via mailing list)
Hi,

On Sunday 18 February 2007 13:16, SonOfLilit wrote:
> Say, why not just define Object#mutable? and solve the issue of not
> knowing if dup is possible or not?

In my opinion, this exposes at the ruby level an implementation detail
that
pollutes the language design, and you must add it to the "weird things
you
should remember".

Please, compare

def a
  obj = some_method
  raise 'hey!' unless obj.mutable?
  do_stuff obj.dup
rescue SomeMethodError
  pull_out_the_power_cord
end

to

def a
  do_stuff some_method.dup
rescue SomeMethodError
  pull_out_the_power_cord
rescue TypeError
  raise 'hey!'
end

I think that the whole design is clear and makes sense, you can call a
method,
and you should catch exceptions, if you care about them. Or let them
stop
execution, if needed.

> Sure, it only works to tell you about one possible reason it's not,
> but it seems like a good workaround, far better than, say, duping just
> to check.

Why should "dup" behave differently than all the other methods that
raise
exceptions when something exceptional happens? :)

my 0.02c
7b4707f974af261f71943e1f2046c9ee?d=identicon&s=25 SonOfLilit (Guest)
on 2007-02-18 14:23
(Received via mailing list)
On 2/18/07, Marcello Barnaba <bofh@softmedia.info> wrote:
> Please, compare
>
> execution, if needed.
>
> > Sure, it only works to tell you about one possible reason it's not,
> > but it seems like a good workaround, far better than, say, duping just
> > to check.
>
> Why should "dup" behave differently than all the other methods that raise
> exceptions when something exceptional happens? :)
>

Because it's something exceptional that is very predictable and we
might want to know about it in advance.

My workaround is an addition, not a modification. For most cases,
rescue TypeError is perfectly fine, but sometimes we might want to
validate that a received object is dup-able at the beginning of a
method, before doing some hard work that would only _later_ require
duping it.

That's why I support having a way to know if oyu'll be able to dup.
> my 0.02c
> --
> pub 1024D/8D2787EF  723C 7CA3 3C19 2ACE  6E20 9CC1 9956 EB3C 8D27 87EF
>
>


Speaking of which, why IS mutability of certain objects left as an
implementation detail? I think we assume mutability/immutability of
objects a LOT at coding time, and for a different implementation to do
otherwise would certainly have performance implications and probably
even make code written for say MRI break, isn't it so?

Perhaps mutability/immutability should be in the spec?


Aur Saraf
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2007-02-18 19:10
(Received via mailing list)
Hi --

On Sun, 18 Feb 2007, Greg Hurrell wrote:

> specific object and want to keep track of it, including changes in its
>
>  @my_var = value.dup
> punctuation. Try passing in a Fixnum though; you'll get an exception
> singleton-but-mutable object, but I assume that if you know enough
> mutable classes normally just return self if sent the "copy" message.
>
> An even more elegant solution, however, would be to extend
> "attr_accessor" and friends to allow the programmer to specify if
> attributes should be set "by copy" or "by reference". This is exactly
> what the new Obejctive-C 2.0 provides. In those cases where you want
> to override the default behaviour you would do a
> "attr_accessor_bycopy :my_var" and Ruby would do the right thing. Of
> course, there is nothing stopping me from writing my very own
> "attr_accessor_bycopy" method, but it would be nice if it were a
> feature of Ruby itself.

One problem with this is that dup oeprations don't fall precisely
along the lines of a by value/by reference/by copy categorization.  If
you do this:

   a = "hi"
   b = a.dup

you're assigning to b a reference to a dup of a.  If you do this:

   b = a

you're assigning a reference (the one in a) by value to b.  This stuff
won't necessarily transliterate well from another language.

I'd rather just keep what's happening on the surface: if you want a
dup of an object, then call dup on it (with error handling if
necessary).  I think that's better than add a new layer of terminology
to Ruby method names.  (I'm also not sold on the idea of a method
called "dup" harboring the possibility of silently returning something
that isn't a dup, as discussed earlier in the thread.)

Maybe we'll go down the road of flags some day:

   attr_reader(:dup => true)

or something....


David
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2007-02-19 08:57
(Received via mailing list)
Hi,

In message "Re: Oppinions on RCR for dup on immutable classes"
    on Sun, 18 Feb 2007 02:54:42 +0900, Stefan Rusterholz
<apeiros@gmx.net> writes:

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

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

I don't deny your model, but it smells like static typing.  In Ruby,
we do

  obj.dup

not,

  void foo(SomeClass obj) {
    obj.dup();
  }

We don't see any class in Ruby example, we just see an object, and
order it to dup, assuming it can dup itself, without knowing whether
it is really able to dup.  If it can't, for some reason, it raises an
exception.  The best illustration for the situation (in Ruby, not
being Java) is something like above "sit and order" model.

              matz.
This topic is locked and can not be replied to.