http://www.perlmonks.org?node_id=125086


in reply to Paradigm Shift - Don't use strict

<rant>
In fact, merlyn refers to the above style as Cargo Cult programming. Is it a class method? Is it an instance method? Why is that there?

With all due respect to merlyn, I have encountered this post in the past and frankly was quite disappointed, neigh, shocked at what he had written. At the time I decided that as it was an old post and given that I was a newbie here it was inappropriate to criticise such a senior monk and icon of the perl community. However since then I have read various discussions about newbies not being afraid of commenting when they think they should and the fact that you bring it up here has made me change my mind:

Lets consider merlyns rational for not having a dual use new()

If you want an instance method called "new", I have no idea what it's doing. If you want to clone an object, call your instance method "clone" or "copy".

So it would appear that merlyn doesn't read the documentation of the modules he uses. The documentation should specify the exact semantics of a method, including whether it can be called in object or class context, and what it should do when it is.

Now I agree if the documentation does not explicitly state that the new() is both a class/object method it probably should only be a class method. But this is perl, which as we all know if phenomenally flexible language, where part of that flexibility allows for exactly such behaviour. In fact one could almost argue that providing such behaviour goes along with the perl philosophy. After all subroutines are allowed to know if they have been called in list or scalar context, and change their behaviour accordingly, so whats the problem if constructors do the same?

Yes, there are other prominent members of the Perl community who disagree with me on this. Ask them if they were programming in Smalltalk in 1980. {grin}

And now we see what is quite frankly one of my pet peeves: The ascribing of protocols and conventions from one language to perl. Frankly I couldnt give a toss what smalltalk users did in the 80's or what they are doing now. Nor do I care how Java does things or VB or C or C++. (Except when I use them :-) So lets provide a modern equivelent of merlyns misguided words:

And just cause it annoys me so much how about a perlish one:
Update:changed 60's to 70's as per tillys email

Which IMO is as absurd as merlyn saying Perls constructors should conform to the conventions of Smalltalk. (And yes, I know that Smalltalk was the groundbreaking OO language. Consider that ALGOL/FORTRAN/COBOL were also a groundbreaking languages from the past, have you ever heard anyone arguing that we should comply with the conventions from them?

I consider any use of this ref($proto) || $proto in new to be "cargo cult programming", and mark it off as such in the code reviews I do.

To be quite frank I lost a lot of respect for merlyn when I read his post, but this line was the whammy. (Oh and its ok that I lost a lot of respect for him over this, theres still lots of respect left :-) Anybody that says 'any use of x is cargo cult programming' without giving damn good justification for the comment, is advocating cargo cult programming. And IMO the reasons that merlyn has given in his post for not using this construct are weak, verging on ridiculous.

If I was in a class where I lost marks for doing such a thing in perl because my teacher thought that I should write my perl to reflect the conventions of another language (one that I may or may not be familiar with) I would not rate the teacher very highly, in fact I would probably demand my money back. I mean imagine the scenario, there you are using closures and a hash to dynamically generate accessors for an class, and the teacher marks you down because you haven't set them up as they do in Java! Bah! I signed on for a Perl course mate, not how to do Smalltalk/Java in Perl!

OTOH:

My issue here is with merlyns justification and his knee-jerk approach to the issue. It should be understood that I am not necessarily advocating the use of dual use new()s.

I usually provide dual use constructors in my objects, primarily for eas of use and brevity reasons (I dislike sprinkling classnames through my code, especially long ones :-) but I recently discovered what I consider to be a good reason to follow merlyns advice:

C++ programmers like to use the indirect syntax for creating objects, instead of using the more perlish direct syntax. But sometimes they use both:

my $obj=new CLASS($arg1,$arg2); my $obj=CLASS->new($arg1,$arg2); my $mistake=new CLASS->new($arg1,$arg2);
When they make this mistake with an object that doesnt provide for dual use constructors they will get an error, when it does they will get an object. But depending on the semantics of the constructor they may get a very different object than they thought. For instance if the new() is a plain vanilla constructor in object or class, the arguments wouldn't be passed to the second call of new() resulting in a different object. Of course the story would be different if the new() in object context was a clone method.

So the bottom line is that yes there are some minor issues with dual use constructors, but no they definately are not outright wrong, much less cargo cult programming.

</rant>
Yves / DeMerphq
--
Have you registered your Name Space?

Replies are listed 'Best First'.
Re (tilly) 2: Paradigm Shift - Dual Use Constructors
by tilly (Archbishop) on Nov 13, 2001 at 22:07 UTC
    I disagree that this is just a protocol or convention from another language. There is a lot more to this issue.

    The heart of this question is what your model of OO programming is. The ref trick makes Perl halfway towards being prototype based, but not really. Avoiding it allows you to have a model closer to Smalltalk's, which works much better in Perl. Given that I prefer Smalltalk's model, I am inclined towards merlyn's position. But given that the ref trick can't make the prototype approach work, I think that he is objectively right.

    (Those who don't know what I am talking about when I talk about prototypes should read the explanation I gave at A Cat's eye view of OO.)

    If you want to take a prototype approach in Perl, you can. Do it with BikeNomad's Class::Prototyped and have it work right. Don't do it with a half-way hack that allows you to maintain a bad mental model of your code that won't really work if you push it.

    Furthermore merlyn's accusation that it is typically cargo-cult programming is definitely on target. Take 10 random people who regularly use the ref meme in their constructors. Of them at least 8 have never given any serious thought to the question of why they would want to write code that way. They have no clear thoughts on it at all. They have just seen the construct, use it because they have seen it, but they have no strong thoughts on what the reason is. That is exactly what cargo-cult programming is. The blind repetition of programming patterns that you have not thought about and do not understand.

    And about the two other examples you gave. Steve McConnell was circumspect about saying how bad Hungarian Notation is in his classic Code Complete, but what he said there about why it is bad is exactly correct. And it was correct coming from someone who had (among other things) done VB programming for Microsoft in the 90's. Secondly nobody programmed in C in the 1960's. It wasn't invented until the 70's. Even if it were, the use of context in Perl is something a C programmer should have no opinion on since the concept doesn't exist in C. By contrast the use of objects in Perl is something which a user of another OO language reasonably can have opinions on in Perl because it exists both places. Their opinions might be wrong for Perl, but they at least have an experience base which is somewhat relevant.

      "Cargo cult" programming is evil only if it's a lifetime pattern. As a part of larval stage, it's entirely normal. Human beings learn, in part, by imitating what they don't understand ... yet.

      For further information, see any human child.

          -- Chip Salzenberg, Free-Floating Agent of Chaos

        I've come to hate the term "cargo cult" myself. Many people copied that constructor code from standard documentation. I thought such copying was more accurately called "best practices".

                - tye (but my friends call me "Tye")
        "Cargo cult" programming is evil only if it's a lifetime pattern. As a part of larval stage, it's entirely normal.

        Many of the complaints that I see merlyn and other making against Cargo Cult programming are in the context of production code.

        Granted, we're all larva at some point, but on my projects, I try to avoid letting larva write production code.

        That may sound snotty, but a lot of what we do here is try to get people past the larval stage by pointing out what's bad about what they're going, and pointing out what they could do right.

      Tilly perhaps ive missed your point, but you seem to be doing the same thing as merlyn. You are trying to apply OO models from various languages to Perl. OO is a simple idea: the strong association or binding of procedures with the data that they manipulate. Everything else in OO is an extension of this simple concept. Now many languages embraced this idea and as mathematicians (think i)and computer science types often do extended the idea to its logical limits, or beyond in some cases, to see what the implications, pros cons etc of such systems.

      But these ideas (prototypes, inheritance, polymorhism, overloading....) are just additional concepts that have been added (or not depending on the language) because of the interests, predilictions and whathaveyou of the various authors and users of the various languages. The fact that they are often useful or desirable features of a language does not mean that they are necessary, much less right.

      Im happy that you prefer smalltalks OO model, and even happier that perl provides what is necessary to emulate it. But not because I like the smalltalk model but because I like the perl model, where I can do all kinds of things, only a few of which are considered to be standard OO techniques.

      Now as I said, I have come to agree with merlyns point, but not for any of the reasons he provided (which were, to be blunt, crap). You said: The blind repetition of programming patterns that you have not thought about and do not understand. Well Im sorry but to me that is exaclty what merlyns statement about marking people down whenever he saw the construct is. The blind application of a rule of thumb without trying to understand why it was done. For instance I have written a number of GA implementations in perl (unpublished sofar). Now I have a class GA::Entity in my model. This class is used to represent a solution in the GA. When I call GA::Entity->new() it returns a randomly generated solution. When I call $ga_entity->new() it produces a randomly mutated version of $ga_entity, and when I call $ga_entity->new($other_ga_entity) it returns a cross of the two. I thought long and hard if I wanted this type of behaviour and experimented with a number of alternatives before deciding I was happy with this approach. But of course merlyn would mark me down bigtime without considering why I had done it, and what my reasons were. And that my friend is plain and simple Cargo Cult Programming.

      Now, Ill grant that if merlyn had said something like "Well, generally I dont think this is a good idea. If I saw this in a code review I would want to see good justification for doing it, and a healthy amount of documentation to explain what is going on" or something to that effect then my attitude would be very different. Also I will grant that if the users of this construct are as you allege unaware of the issues related to it, then indeed it is cargo cult programming as well, but this doesnt change the fact that merlyns comments are too.

      I think you might want to reread my sarcastic comment about hungarian. I was trying to come up with the equivelent of a perl guru advocating the use of hungarian in perl.

      As for the C/Context point, I dont agree. To me there is little or no difference between someone who has experienced a (different) concept or not experienced the concept at all in a given langauge demanding that a second language behave the same way. That quite possibly is why they are different languages.

      Your last sentence is to me the key here, Their opinions might be wrong for Perl, but they at least have an experience base which is somewhat relevant, yes their opinions are relevant but not necessarily correct. And that is exactly what I think of merlyns post. Relevent and wrong.

      Yves / DeMerphq
      --
      Have you registered your Name Space?

        I disagree on whether merlyn's comments on this topic are Cargo-Cult programming. To say that it is is to say that this is a topic that he, has not thought about and does not understand.

        To the contrary, merlyn has done OO programming for 20 years, and has done OO programming in Perl for as long as Perl has had support for it. In that time he has seen many different approaches to OO programming, in quite a few languages, and has developed strong opinions on the subject. I would be very, very wary about claiming that he has not thought about the relevant issues, or claiming that he doesn't understand OO programming in Perl.

        Now Perl's OO is, you claim, a simple idea. Not so fast. Perl's OO is a simple implementation of a fundamental concept. The fundamental concept behind OO programming is that it provides support for modelling your programming universe, and then later using that model to find good solutions for your problems. The implementation in Perl is simple partly because other features in Perl make it easy to do whatever you want. The amount of OO specific flexibility that needs to be added is little, but the OO model you get is more complex. And the potential OO models are even more complex.

        So back to what OO is. I claimed that OO is about ways of creating conceptual models and then working with that. The key idea is indeed to create "things" that you can interact with. The things contain internal data, and are bound to methods. The modelling tools that you use to create your models of the things vary, but modelling is the job.

        Now if you are going to be modelling, then it is important to think about what kinds of models you want and why. And part of that is your model of what the relationship is between a class and an object in that class. merlyn's point, and mine, is that when you use the ref || $proto trick, what you are really doing is making it possible to confuse the object and the class. As I, and merlyn, point out, this confusion will only work partway. While sometimes the effect can be useful, most of the time the model is misleading.

        Which is why I say that most of the time you should either not do that, or else you should go the rest of the way. I am not saying that you should program Perl like it was Smalltalk. I am saying that to whatever extent possible you should encourage clear mental models of your classes. Don't reflexively type in an idiom because you have seen it. Stop, think about whether it is what you want, and then conciously choose whether you want it.

        Now to address a fundamental issue. While it is true that when merlyn is hired to do a code review, he flags that item, my experience is that this is a provisional opinion. If you point out why you did it, and have a reason, he has no trouble going, "OK, you know what you are doing" and takes back what he said. It is like strict. Most of the time it is a danger flag. But sometimes, based on what the code is doing, strict really can't be used. The rule that is true 95% of the time isn't always true.

        For instance take a look at Re (tilly) 1: Nested Classes for an example where I used the ref||$proto idiom. As I commented in the code, it wasn't Cargo-cult. And merlyn sent me a private note about that when he says that he only minds seeing that construct in the code of people who don't really understand what is going on. But he says that in that code he would not have flagged it.

        And a final few corrections. First of all I think that other languages can do a lot more with OO than you give them credit for. Secondly mathematicians do not do anything particular with OO, in fact most do not even know what the heck it is. And finally given my background, I am far more likely to see other languages through Perl tinged glasses than vice versa...

        When I call GA::Entity->new() it returns a randomly generated solution. When I call $ga_entity->new() it produces a randomly mutated version of $ga_entity, and when I call $ga_entity->new($other_ga_entity) it returns a cross of the two. I thought long and hard if I wanted this type of behaviour and experimented with a number of alternatives before deciding I was happy with this approach. But of course merlyn would mark me down bigtime without considering why I had done it, and what my reasons were.

        I fail to see how someone would mark you down on this, because you wouldn't have the traditional my $class = ref($proto) || $proto, you would have something much more complex wrapped around:

        if (ref($proto)) { if (ref($_[0])) { cross polinate } else { mutate } } else { construct new }
        Which would look far more reasonable in a code review, and would almost inevitably have to be documented. So I don't buy your argument.
      tilly: Furthermore merlyn's accusation that it is typically cargo-cult programming is definitely on target. Take 10 random people who regularly use the ref meme in their constructors. Of them at least 8 have never given any serious thought to the question of why they would want to write code that way.

      I know what it does, I know when I would use it, but I honestly can't remember when I've actually utilized a prototype, yet I continue to put the 'ref($proto) || $proto' stuff in my code (I think I may have actually used it once but I'm not sure). In a code review with a 'perl master' (not merlyn) at the conference I pointed out that I'm not sure if its all that useful but he assured me that it was fine. I figure that it has become such an idiomatic perl thing that if you don't do it that way, you take the chance of disappointing someone down the line who might want to utilize it (yeah, it's a weak excuse).

      merlyn: I consider any use of this ref($proto) || $proto in new to be "cargo cult programming", and mark it off as such in the code reviews I do.

      Hah! beat ya to it. Though I continue to use it, I mark myself off first (and this is what I had in the 'code review'):

      sub new { # Do the cargo cult OO construction thing my $proto = shift; my $class = ref($proto) || $proto; ...
      The heart of this question is what your model of OO programming is.

      Is it? I'd say that for me, this boils down to the following considerations:

      1. Do you want to or need to permit someone to call either $obj->new() or (ref $obj)->new()? (Typically, no. Consequently, on those occassions where I've done this I've got to admit it has been cargo-cult. But now that I'm aware of this, I come to the next question...)
      2. Even if you don't need this, are you going to permit this anyway? Are you going to allow someone else to do this with your module, and to do this as a direct object method, without calling ref($obj)? (And here, my answer is "Why not -- how could it hurt?")
      3. If you say 'yes' to either of the above, are you confused by the name of the method new(), so that you don't know if it clones or not? And my answer is, "No! If I wanted the method to clone, I'd've named it clone() and not new()!"

      In short, for me it's a matter of interface preferences, and how strict/permissive I want to be with that. The philosophy of it all only comes down to the simple question of whether it makes sense for new() to ever behave as clone(). To me it doesn't; this may be because I only really learned OO via Perl (and some Java) so I'm not influenced by Smalltalk or other languages.

      -- Frag.
      --
      "Just remember what ol' Jack Burton does when the earth quakes, the poison arrows fall from the sky, and the pillars of Heaven shake. Yeah, Jack Burton just looks that big old storm right in the eye and says, "Give me your best shot. I can take it."