May 14

More Sub Confusion

Author: s1n
Category: 01100011

You know something is afoot when I start blogging more regularly.

This is starting to feel like a poetry slam from the 90’s. I wanted to take a minute a respond to moritz’s response to my article lambasting the confusing nature of subroutines and methods.

So pmichaud showed up late to our Perl6 Mongers meeting and resolved the whole mess. He explained that subs are the typical subs from perl5. They have no invocant associated to them and they are scoped to the class or package they are defined in. Oh yeah, in classes and modules are just sugarized packages.

Methods on the other hand require an invocant, such as an object or self. This as supposed to eliminate the confusion about how subs worked in perl5.

The source of confusion seemed to stem from my original thought that a sub in a class was something akin to Java’s Class-level function or c++’s public static function. pmichaud explained that there really is no such thing and the only real difference with subs from perl5 is the addition of method to indicate an invocant is required. Also, “$.method” and “$_ = self” hacks don’t really work and the latter leads to seriously dangerous code.

However, pmichaud said that self will generally be required when calling a method from a method (within the same class/package/module). The second example I gave is a legitimate gripe. In fact, pmichaud said that I am definitely not the first person to voice a complaint about it.

In case you can’t recall my kvetch about this issue, the following requires the self invocants:


class A {
method foo { ... };
method bar { self.foo; };
}

I can’t just call foo without the self invocant. The problem I have is that it’s not implicitly passed to the foo function for me. Everyone’s argument is that this smells too much like the problem with subs from perl5. So let me explain myself a bit more.

To be properly Huffmanized, not specifying an invocant from a method should pass self to the method within the scoped class. From a sub, it should call the sub by the name without passing self. That is, this should work:


class A {
method foo { ... };
method bar { foo };
sub baz { ... };
sub zab { baz };
}

So then I was asked, “well how do you call something like IO::open if my class has an open?” Just like that, specify the whole package namespace.

The reason why I expect implicit invocant passing to work is because, from within the scope of a method, I should not have to continue specifing my invocant. This leeds to overly terse code that is not properly Huffmanized like this:


class A {
method s {...};
method t {...};
method u {...};
method v {...};
method w {...};
method x {...};
method y {...};
method z {
self.s;
self.t;
self.u;
self.v;
self.w;
self.x;
self.y;
};

where method z should look more like


method z { s; t; u; v; w; x; y; }

I can work around this by doing clever given (read: Basic/VB ‘With’ blocks) statements:


method z { given self { .?s; .?t; .?u; .?v; .?w; .?x; .?y; }; }

It’s close, but no cigar. Of coarse, I could always be wrong and I’m just looking at the problem from the wrong angle. I’d love to hear any feedback.


tags: , , ,
3 comments

3 Comments so far

  1. frew May 14th, 2009 3:31 am

    Note that the final example doesn’t *require* the .? instead of .

    The .? should run that sub if it is defined but no error if it’s not.

  2. Moritz May 14th, 2009 4:53 am

    If it’s just the syntax that bothers you, you can replace self.foo with $.foo (or @.foo if you want to call it in list context).

  3. s1n May 14th, 2009 10:32 pm

    Moritz: I’m more okay with that than endlessly specifying self. See Tene’s idea. pmichaud pointed out that there’s a bug with that form though.

Leave a comment