2009
07.26

Finding motivation lately has been more challenging than usual. My posts about perl have grown further apart. I have mostly slowed down working on my pet projects. I haven’t been reading my Perl related blogs anymore. Even writing this entry seems forced and unnatural. I hope this post is not picked up by the Ironman Perl planet due to the complete lack of any substantial content.

Don’t be mistaken, I am still interested in all of these things. I have a stack of interesting modules that I want to clean up and release. My feed reader is chock full Ironman Perl entries. I have 2 unfinished posts about Perl 5.

There are several reasons for my recent sloth. The summer is drawing to a near. I have a large list of honey-do items that need to be done around the house. Worst of all, I am working lots of overtime for some projects that are perpetually behind schedule and over-budget.

On the positive side, I have spent a majority of my summer learning about compilers, programming languages, and parsing grammars. I was really taken by the Topaz project, which has been a source of inspiration. I was also very impressed with the PGE presentation and discussion at the Parrot Virtual Machine Workshop.

I have exceeded my ability to maintain my attention about my own blog post. I’d say more about my next post but I just want to stop typing.

2009
07.15

There are a few corrections that were needed from my .WALK talk yesterday. Having the Rakudo pumpking sitting next to you makes answering questions much easier.

First, moritz_ strongly suggested I post working code and not off-the-cuff code anymore. His argument was that it further perpetuates the meme that Perl 6 is vapor. So here’s a properly working example:


class A {
    method baz { ... };
    method bar { ... };
};

class B is A {
    method baz { ... };
    method icanhaz { ... };
};

class C is B {
};

class D is A {
    method ucanhaz { ... };
};

my @candidates;
my C $c .= new;
@candidates = $c.WALK(:name<baz>);
say @candidates.map(*.name).join(', ');
@candidates = $c.WALK(:name<icanhaz>);
say @candidates.map(*.name).join(', ');

So the obvious correction there is the change to class. This is because modules cannot inherit. Also, the named parameters were supposed to use <> or quotes. The say calls were added to see the results immediately (aestetics).

Also, it seemed that in my attempt to understand WALK, I misread the entire intent of the returned results. The WALK iterator will in fact return callable methods (Code objects?). Those methods can then be called with the $* and $+ operators (as discussed in S12). The correct output is:


baz, baz
icanhaz

The two baz methods are B::baz and A::baz, while the icanhaz is just B::icanhaz. Since multi method dispatch never truely hides methods, similar to C++ (Base::method) and Java (super.method), A::baz is still available for dispatching.

Lastly, :name is not required, since it will return all methods. :name, hence why it was bundled in the filter parameter list, merely filters out method name matches.

That should wrap the loose ends. I hope the attendees enjoyed learning about method dispatch and WALK. I’m soliciting for next month’s talk if anyone wants to volunteer.

2009
07.13

I will be putting on the first Dallas.p6m talk about upcoming Perl 6 features. This posting will discuss one of the introspection tools: .WALK.

Note: Any code posted below is for demonstrational purposes. It is left as an exercise for the reader to polish for any compiler or interpreter.

WALK is a function defined on Perl 6 objects that will walk the multimethod dispatch and return the appropriate matching candidates. It follows the entire multimethod dispatch, regardless of whether a version has been overloaded by the child, applying various match/non-match functions and returns the results. Let’s start off with an example:


module A {
method baz { ... };
method bar { ... };
};

module B is A {
method baz { ... };
method icanhaz { ... };
};

module C is B {
};

module D is A {
method ucanhaz { ... };
};

my @candidates;
my C $c .= new;
@candidates = $c.WALK(:name(baz));
@candidates = $c.WALK(:name(icanhaz));
@candidates = $c.WALK(:include(B));

So basically what I did there was set up a cheezy object hierarchy and did a few WALKs over it. Let’s go over them and discuss what they did.

I should note that it is not obvious or clear from the Specs what a few of these options truely entail. For example, unless you are intimiately familiar with dispatch, the various dispatch method orders are not well defined. I keenly opted to skip them.

I should also note that there is very little information in the Spec (S12) pertaining to .WALK. After having written this post, I will obviously need to present a few questions to the mailinglist.

The first call returns < C B A > because they all have the baz method. The second call only returns B because it is the only one of < C B A > that contains the icanhaz sub. The third call returns < A C > because A was omitted from the results. However, there is a slight issue I wanted to raise with the third call. It’s not clear from the spec that :name is a required parameter (:name!). In all likelihood, the :name parameter is required and this call will result in a compile/runtime error.

There are a multitude of parameters that guide the tree traversal:

  • :canonical for canonical dispatch order
  • :ascendant for most-derived first, like destruction order
  • :descendant for least-derived first, like construction order
  • :preorder for like Perl 5 dispatch
  • :breadth for like multi dispatch

There are a few other parameters that help with filtering classes/modules/methods along the hierarchy as WALK traverses the multidispatch candidates:

  • :super to only include immediate parent classes
  • :name to only include classes containing named method declaration
  • :omit(Selector) to only include classes that don’t match selector
  • :include(Selector) to only include classes that match selector

Another thing that the Spec does not discuss is whether subtrees are pruned out from the search or if they are all smashed onto a flat search space and only matches are returned.

So astute readers are wondering what the Selector parameter can be for the :omit and :include parameters. Let me show you an example taken straight from the spectest:


my @cands = $x.WALK(:name< m >, :include(regex { < [CDE] > }), :omit({ .^can('n') }));

How awesome is that?! You can specify a regex or use the .^can attribute. In perl5, the .can attribute returns a single Code reference. The new .^can attribute returns a .WALK iterator, which can be used with either :include, :omit, or all by itself.

This is a really cool way of letting me explore my objects more. To those of use who have wanted to do similar things with other languages, this feature will greatly assist inspecting foreign code for it’s capabilities (and obviously other things). I usually use introspection to find out if a plugin or if a class in a library has a certain capability (think versioning your classes). So to round out this discussion, I wanted to briefly mention what a few other languages are capable of that is similar.

Java has fairly decent introspection capabilities, referred to as Reflection. You can sift through the constructors, the declared methods, declaring class (if inherited), class fields, and even invoke methods. There are no built in techniques to automatically narrow the search space (defaults to the current Class object).

Python has very limited introspection capabilities. Python’s method is significantly more arcane than everywhere else, unless you like __method__() calls. Python allows you to get attributes on a class/object by using the __getattr__() function. I had trouble digging up a complete list of string literal attribute names, so buyer beware. Therefore, I should note that my comparison to Python is probably incomplete.

C++ has no such facilities. In order to accomplish this, you will have to conjur up clever hacks like this macro that is used to create a database of classes. Xlibs provides some legacy functionality similar to this that can be used for classes and functions, but is generally pretty limited. The closest thing to invoking one of the returns from .WALK in C++ is going to be a hand-rolled combination of boost::function and boost::functional.

Ruby has a way to keep track of known object instantiations, ObjectSpace, and then pull out methods (private, protected, public, and singleton) and instance data. This is done through the basic Object class. It can even do something similar to perl5’s .can (respond_to?). Unfortunately, there are also no built in techniques to automatically narrow the search space.

The ability to guide the search of multimethods built into the language is an advantage not found elsewhere. Keep in mind, I didn’t feel like researching all 10 million languages out there to see if this is a truly original feature.

This is getting a bit long to really be considered a lightning talk, so I will end it here. If anyone has any corrections, suggestions, or comments, feel free to use the comment feature.

2009
07.06

At YAPC::NA, Chip Salzenberg held a last minute brief talk that really started making me think. Well, to be honest, the thought process started at the Parrot Workshop but really began in this talk.

I’ve always been fascinated with programming languages and compilers. These things had always struck me as not academically challenging and basically a solved engineering problem. I never really did much in the area except for an undergraduate course where I wrote compiler for TinyC, written in Perl, with a MIPS assembler code generator backend. It was a study in recursive decent parsers, so it lacked any real semantic capabilities, such as symbol tables, garbage collector, or ASTs.

So anyways, back to how this relates to Chip’s laid back talk. Basically, he encouraged people to become core Perl hackers. “Yes, things are bad, but they’re not that bad.” The talk only lasted 20 minutes, but my brain started spinning for the rest of the day. I tried having a few conversations, but I failed to sustain anything more than a few minutes. The talk wasn’t overly special. It wasn’t groundbreaking or funny; it was clearly an impromptu presentation with slides obviously created quickly; it lacked substantial content and it was not thought provoking. It was the perfect talk at the perfect time because my brain was in the perfect state of mind to think clearly and creatively.

So I have since turned my attention away from my thesis for the summer and towards compilers and programming languages. I have started filling my research notebook with all sorts of ideas in the chance that I spark a true flash of genius. My advisor is likely to be annoyed that I decided to change directions radically but he went overseas for the summer and has stopped responding to email.

Thank you Chip, you may very well have ignited my imagination and passion to create something truly worthwhile.