ref ($p5p) || $p5p

Ovid on 2004-04-02T04:16:15

Over on the Perl 5 Porters mailing list, I asked for people's opinions regarding a proposed patch to the OO docs. Specifically, I wanted to simplify them by removing the ref ($proto) || $proto lines in the constructors (and the text references to such). If someone doing OO work finds that they really need this construct, it's trivial to figure it out. As it stands, new programmers get confused -- and flamed -- for this all the time because they add it needlessly.

Given the huge amount of debate over this topic, I expected to open a can of flaming worms. Surprisingly, there's been little debate. I'm rather stunned.


Ok,

jonasbn on 2004-04-02T08:04:52

I propose a change instead of a removal,
ref ($proto) || $proto;
should be changed to:
ref ($class) || $class;
This would keep it in a OOP wording and possibly make it more essential for Perl-OOP beginners to understand what is going on.

The construct is quite essential (I personally always use it).

If you use inheritance, the result of not using could be strange since many people would perhaps not understand why their inheritance does not work and errors, which might be quite difficult to debug will occur - I learned to use the ref function from this.

So some explanation should be added, this explanation is taken from Damian Conway's book 'Object Oriented Perl', page 172, chapter 6 'Inheritance'.

It's essential to use the two-argument form of bless. If the PerlHacker class had used the one-argument form.
longer code example removed...
Then the object returned by PerlGuru->new(@args) would have been a PerlHacker object. The one-argument form always blesses into the current package, not the package through which the constructor was called.

Another thing is, since all Perl programmers are potential CPAN contributors, some may be experienced, but just not used to the OOP way of doing things - and since inheritance is a really good way of moving improving/extending/patching existing OOP based CPAN modules (as suggested by MJD), removing the construct from core documentation could result in less flexible modules, which will require patches etc. before subclassing can be performed.

I now we are not supposed to put things in our code, which we do not understand, but in my opinion, this case its a bit like use strict; - do not ask why, just use it - read, evolve - so how can we read and evolve if the examples from the docs are removed? it is not a good idea.

Was this kind of the thing you where looking for?

Re:Ok,

bart on 2004-04-02T08:27:19

No, I doubt this was the kind of thing he was looking for. You should use 2-argument bless, but not one this complex. The form you ought to be using should simply look like
sub new {
    my $class = shift;
    my $self = ... # any kind of ref, any data
    return bless $self, $class;
}
The idea is that it's bad to make one constructor both for actually making a new object (class method), as for cloning (object method). Probably nobody ever uses new() as an object method, I'm sure. So don't make the API more complex by providing a mostly useless and confusing, and probably buggy, option.

The most active high profile opponent of this complex abomination must be Randal L. Schwartz, AKA merlyn. I'm quite sure he'll step in this discussion at one point, but at this time, I'll just point to one of his posts on PerlMonks.

Re:Ok,

Matts on 2004-04-02T09:03:29

Unfortunately this is a classic example of not understanding it - just copying it.

This has nothing to do with inheritance or the two arg form of bless. It only has to do with being able to call ->new() on an instance of the class, and whether or not that's a good idea.

Most people will never ever do this (as what they really want is a copy constructor, not a "call new on the object" method). I agree that all of these should be removed from the docs forthwith, but not just the docs, I think they should be removed from code within perl core modules too.

Re:Ok,

jonasbn on 2004-04-02T09:13:55

Then I must have misunderstood what Damian wrote... maybe I should reschedule a re-reading of that book.

So this does relate to cloning of objects as bart writes in his comment earlier.

Hmm don't mind me - I just need to do some reading and experimenting...

Re:Ok,

jonasbn on 2004-04-02T09:53:00

Ok, now I read the docs on bless and AFAIK I can see I copied something without clearly understanding it - WHOOPS!

Well the recommended syntax mentioned in the documentation should perhaps read:
bless ... , (ref class);
Instead of:
bless ... , (ref class) || $class;
It is custom to buy a kvajebajer in Denmark if you make an obvious mistake like this, so Matts or bart if I meet you some point remind me that I owe you a beer.

And perhaps an excuse to MJD for not paying attention :)

Re:Ok,

jonasbn on 2004-04-02T12:18:17

Sorry,

The recommended construct should of course read:
bless ... , $class;
Hence the ref and || are the elements, which should be removed.

Re:Ok,

Ovid on 2004-04-02T15:07:29

No offense, but I think your suggestion of changing it to ref ($class) || $class; actually demonstrates the problem we're trying to solve. Specifically, this is bad:

sub new {
  my $class = shift;
  $class = ref ($class) || $class;
  bless {}, $class;
}

I would mark that down on a code review because in this case, the line in controversy makes it clear that you expect to be able to pass in either $self or $class. Since you don't know what it is when you call the constructor, having my $class = shift; is misleading, so calling that variable $proto makes it clear that you're passing in a prototype (actually, at my work, I've found that we have a convention of calling it $class_or_self).

The real problem, though, is not whether this bit of code is useful. It certainly is when you need it. The problem is that it's copied blindly and detracts from learning OO Perl, which is what those docs are about. Having that mysterious ref ($proto) || $proto line in there can strain a new programmers brain, particularly when they see it so much that they begin to think that this is just somehow part of OO, even though they're not sure exactly why. I've pointed this out to programmers who tell me "But it's in the docs!", as if they're some sort of sacred text that should not be deviated from. The intent is to simplify those docs so that programmers can learn OO without getting distracted by bits that they probably don't need.

It's also interesting that you brought up the two-argument form of bless. I mentioned offhand that the one argument form should probably be removed, but I didn't actually propose that. Now I'm beginning to wonder if I should :)

What I said in P5P

merlyn on 2004-04-02T13:01:43

And not to be fighting this debate in multiple domains, but just for the record, here's my contribution to P5P:
Here's what I said on an upcoming SysAdmin column (archived at my site, but not available yet per publisher embargo):
    And now, before I run out of space, let me touch on a hot-button for
    me.  The I<perltoot> manpage contains an archetypal C<new> routine
    that looks like:

      sub new {
        my $proto = shift;
        my $class = ref($proto) || $proto;
        my $self  = {};
        ...
      }

    The purpose of these few lines of extra code is to permit:

      my $other = $dog->new;

    to act like

      my $other = (ref $dog)->new;

    But here's the problem.  When I survey experienced object-oriented
    programmers, and ask them what they expect C<new> means when called on
    an instance (without looking at the implementation), the result
    usually divides rather equally into three camps: those that go "huh,
    why would you do that" and think it should throw an error, those that
    say that it would B<clone> the object, and those that say it would
    B<copy> the object's class but not the contents.

    So, no matter what you intend if you make your C<new> do one of those
    three things, two thirds of the people who look at it will be wrong.
    It's not intuitive.  So, don't write code like that, and especially
    don't just cargo-cult that from the manpage into your code.  If you
    want an object B<like> another object, use C<ref> explicitly, as shown
    above.  If you want a clone, put cloning code into your package, and
    call C<clone>, as we saw earlier.
I'll let these words stand as probably the clearest rendering I've had on the subject so far. :)

Re:What I said in P5P

dws on 2004-04-03T19:36:15

There was a similar discussion at one point in a corner of the Smalltalk community, but without the "it should make a copy" camp (since folks in the Smalltalk community were painfully aware of the differences between a deep and a shallow copy). As I recall, the concensus opinion was that it's easy enough to say
  newObject := someObject class new
which is the equivalent of
  $newObject = (ref $someObject)->new
The only instance-side new I could find when I went looking through an old VisualWorks image was in an addition (a filein) that was of dubious quality.

•Re:What I said in P5P

merlyn on 2004-04-04T01:12:31

Actually, I believe the proper idiom in Smalltalk-80 (and thus Squeak) is: newObject := someObject species new because "species" returns "the class that can make something like this". "species" defaults to "class" for most classes, but check to see where it's defined (and thus overriding class): it's quite fascinating.