in reply to (Re:)+ $class = ref $class || $class
in thread Constructor/Factory Orthodoxy

Howdy!

In the discussion, the point of contention is the use of the idiom ref($proto) || $proto (typically in a constructor), particularly to allow one to call the constructor with an object instead of a class name. Good arguments have been advanced and referred to as to why this practice should be avoided, or at least used with much greater deliberation than would appear typical.

I am taking as axiomatic that the documentation of the module will adequately cover how one might call the constructor (as well as other methods), including some mention of what one might expect from calling it with an object instead of a package name. I do realize that I am subject to disappointment with that assumption.

When I fussed about attributing choices to "mindless imitation", I was a bit unclear. The words I responded to seemed to claim that mindless imitation was the only explanation, and I objected to that apparent generalization. I make no claim to being free of that fault, myself. I think I have gotten better at recognizing it in myself.

When I query about the calling class methods as object methods, I fully realize that the distinction is not inherent in Perl. However, if I have a subroutine in a package that expects an object that isa(__PACKAGE__) as its first argument, such a subroutine has the appearance of being an object method. If that subroutine expects the first argument to be a package name, then it has the appearance of a class method. If that "class method" uses that package name as data, such as blessing a new object, then it is fair to ask how one would expect that method to behave if that package name were actually an object. If the "class method" makes no use of that first argument, then it makes no difference whether it is called as a "class method" or as an "object method". Returning to my axiom, I expect the documentation to help me out here.

Now, if the documentation says "don't you dare call the class methods with an object, or bad things will happen", you, the user, Have Been Warned.

On a more concrete level, if I am faced with $obj->method, and I need to discern which instance of "method" is being called, I'm going to be in for some work, no matter what. If there are multiple modules that might have "sub method" in them, whether I say ref($obj)->method or not will not affect the order of magnitude of the search.

A nitpick: (ref $foo)->method($foo) is not quite the same as $foo->method; the first passes two arguments -- the second but one. The additional argument in the first form does not provide additional information, but it is not quite correct to say that they "pass the same info".

I suppose that part of my perspective is that I don't have any particular problem with the concept of calling "class methods" with objects. I have not yet come around to the viewpoint that overloading that particular semantic facet is necessarily a Bad Thing. As I noted earlier, we may simply have to agree to disagree on this point. I certainly may be no more than a stubborn git. I cannot deny the possibility.

yours,
Michael

Replies are listed 'Best First'.
(Re:)+ $class = ref $class || $class
by rir (Vicar) on Mar 05, 2003 at 22:19 UTC
    Our differing opinions seem to come from the context we each envision when we think of coding. You seem to see the coder sitting down to write fresh code, I see the coder sitting down to look at existing code that needs to be understood and fixed or rewritten. That is how I spend most of my time and I am writing my own code from scratch.

    I don't have any particular problem with the concept of calling "class methods" with objects

    Likewise. I don't have a problem with that, I don't find the distinction "class" method very useful in Perl. In the case of new giving the reader more information about the type of the object can ease the understanding of code using that object. The reason to make my suggested usage a habit is that code can grow, an intermediate call may be inserted into your code; or code-text may be added around your construct making pertinent info more remote; or the type-tree may expand making the code more abstract.

    if I am faced with $obj->method, and I need to discern which instance of "method" is being called, I'm going to be in for some work, no matter what. If there are multiple modules that might have "sub method" in them, whether I say ref($obj)->method or not will not affect the order of magnitude of the search.

    You are exactly right. But the writer who says (ref $obj->method is explicitly telling you that the search is necessary. And the writer who says $obj->new when he knew that Obj->new was equivalent is abusing you unnecessarily, certainly there are some cases where the abuse is very minor, until the code grows.

    A nitpick:(ref $foo)->method($foo) is not quite the same as $foo->method; the first passes two arguments -- the second but one. The additional argument in the first form does not provide additional information, but it is not quite correct to say that they "pass the same info".

    Counter-nit: As you say The additional argument ... does not provide additional information so the statement is correct. I was trying to avoid the word pass but everything else I thought of seemed to relate to informing the reader of the code, which seemed more misleading.

    I ... may be ... a stubborn git.

    I won't dispute this, we both have demonstrated, ahem, a willingness to argue at length over minor issues. In that willingness I see fortitude and some concern for others and for truth. I am trying to share a Good Thing. I am not finding new ways to be more convincing on this so I'll let the subject lie.

    I certainly am not going to have angina over this subject, I hope steves is not too worried for me. :-)