TMTOWTDIAYSSSITFD

chromatic on 2007-05-21T01:38:11

(... And You Should Show Several In The Fine Documentation.)

I find this code seriously confusing:

my $proxy = HTTP::Proxy->new();

# create a new HTTP::Recorder object
my $agent = new HTTP::Recorder;

Besides the fact that indirect object syntax Just Doesn't Work according to a complex series of rules that almost no one can explain properly, I don't understand the purpose of mixing the direct and indirect constructor calls within two lines of code.

I'm all for TMTOWTDI if and when it allows people to choose the most effective approach for solving the particular problems they encounter, but mix and match coding styles within the synopsis of documentation baffles me. HTTP::Recorder is not the only offender; it's just the first one to catch my attention today.


Meh.

educated_foo on 2007-05-21T04:15:18

Sometimes one syntax reads better, sometimes the other:

$bob = new Servant;
$bob->fetch_me_a_drink('please');

I think "Blah->new" always reads badly, but that's a matter of personal taste.

Re:Meh.

chromatic on 2007-05-21T04:53:14

Sometimes one syntax reads better, sometimes the other:

I'm sure Perl would read as better English without the sigils or the punctuation characters too, but if the code doesn't work, it's difficult to justify using it for practical purposes.

Re:Meh.

educated_foo on 2007-05-21T05:27:45

Yeah, and we'd all be better coders if we bent our style to your whims without your even having to express them. But alas...

Unless one's doing something pathological, the indirect syntax works. If someone really doesn't care about (relative) readability, they just use Lisp or Postscript or Smalltalk, where everything really is an X, for their favorite value of X.

Re:Meh.

Aristotle on 2007-05-21T06:10:48

How is one more readable than the other? Perl is an artificial language with artificial rules.

Re:Meh.

educated_foo on 2007-05-21T06:30:09

This is a terrible argument. Why do some people prefer to write "arg0.function(arg1, ...)" instead of "function(arg0, arg1, ...)" in single-dispatch languages? It's all just a matter of convention, but the former suggests "sending a message to an object," which seems to make some people happy (and make others money). Other people like "natural-language syntax" according to their natural language of choice.

Re:Meh.

chromatic on 2007-05-21T06:51:48

Unless one's doing something pathological, the indirect syntax works.

The indirect object syntax can break depending on which methods someone has declared in other namespaces.

It's hardly "pathological" to use namespaces.

In my mind, it's silly to hope that those collisions never occur. They're not easy to debug.

Re:Meh.

educated_foo on 2007-05-21T15:04:43

It's hardly "pathological" to use namespaces.

Save the hyperbole for UNIVERSAL::isa ;). Namespaces, like functions and variables, are programming language features that can be used in both beneficial and harmful ways.

The indirect object syntax can break depending on which methods someone has declared in other namespaces.

The case I think you have in mind is this:

package A; sub f { print "a" }; f B; package B; sub f { print "b" }; package main; f B
which prints "ab". So the problem occurs only when (1) you use a function from B before it's declared, (2) you use indirect syntax, and (3) you declare a function of the same name in A. I think doing all three of these things at the same time is pathological, perhaps because my C background tells me that you should declare things before using them. *shrug*

Re:Meh.

chromatic on 2007-05-21T18:30:51

I think doing all three of these things at the same time is pathological...

Have you used a large system written in Perl, such as Catalyst or Plagger, which supports plugins and loading schemes far different than bare use? It's not always easy to know who loads what when, especially when you use generated and non-generated classes with similar naming styles.

Point taken

educated_foo on 2007-05-21T19:07:49

I don't generally use any Perl swarming with plugins -- the most complex package I've used has probably been PDL. So for me, "'use' it before you use it" has always been easy and effective. You're right that in these hairy cases, indirect object syntax is probably dangerous. On the other hand, (1) most, or at least many, people probably don't use Perl this way, and (2) these systems would probably be improved by having more predictable loading semantics.

Re:Point taken

chromatic on 2007-05-21T20:35:26

You're right about points 1 and 2 as well. Still, I see the indirect object syntax as susceptible to breaking due to action at a distance. When you load a module that otherwise behaves as a properly-encapsulated black box, it may do things that cause the indirect object constructor calls to fail.

I can imagine otherwise-innocent changes to Test::MockObject that would do such a thing. (I'll never do them, unless there's no other way to accomplish something else, but I could justify that code except for the completely bizarre error messages it would generate when the indirect calls fail.)

WTF?

Ron Savage on 2007-05-21T04:33:18

Sometimes $obj = new Classy just does not work, right?
So, $obj = Classy -> new() is always correct.
If you don't get it, /you/ have a problem.

Re:WTF?

chromatic on 2007-05-21T04:55:41

Sometimes $obj = new Classy just does not work, right?

Exactly, and sometimes for legitimate reasons. Plenty of normal things in Perl can fail if someone's being very tricky, but this is one of those corners where the parser needs to know some very precise information at the point of compilation. If that information isn't available, it has to guess, and there are several inferences that it can make incorrectly.

Inconsistent Documentation

davorg on 2007-05-21T08:17:06

I often see this when people are copying code directly from the documentation for a module. Beginners don't understand that

my $foo = new Foo;

and

my $foo = Foo->new;

are just two ways of writing the same thing. They can be forgiven for assuming that classes that use the indirect notation for the constructor must be used that way as, almost certainly, they've never read anything that tells them otherwise. It's really the module authors who need to be educated into cleaning up their documentation.

my $proxy = HTTP::Proxy->new();

# create a new HTTP::Recorder object
my $agent = new HTTP::Recorder;

Of course, once you're at the level where you're submitting your own code to CPAN. Then, yes, it would be nice if you understood subtleties like this.

Re:Inconsistent Documentation

chromatic on 2007-05-21T08:31:37

I suspect that a lot of Perl programmers think that new is an operator in Perl, as it is in other languages (such as C++ and Java).

It doesn't confuse me that novice programmers copy and paste from synopses into code (that's why we have synopses in the CPAN POD form!). What confuses me is the juxtaposition of both forms of constructor call in the same section of code.

My other favorite

jk2addict on 2007-05-21T13:50:30

Aside from any cult stati about which exception module is best in perl, I have to work to make sure my brain stops doing this (from the pod):

throw Error::Simple "Oops!";
and keeps doing this:

Error::Simple->throw("Oops!");
I'd never do that with "new", yet for some reason, my brain was perfectly happy with indirecting 'throw'.