There's more than one way to do things | |
PerlMonks |
Poor Man's Perl6 Exegesis (you get what you pay for)by Ovid (Cardinal) |
on Jan 24, 2002 at 06:21 UTC ( [id://141113]=perlmeditation: print w/replies, xml ) | Need Help?? |
I've been trying to keep up with the latest news on Perl6 and I though it would be a good idea to go through some of the code and try to figure it out. The following is similar to TheDamian's Exegeses. The major difference is that he is much smarter than I and he's kept up with Perl6. Further, I don't have all the answers and I have a heck of a lot of questions. The following is BrentDax's first run at creating the Perl6 Exporter module. He states that he typed the code directly into his mail program, so no fair holding anything against him! Also, this is being posted in meditations rather than SOPW because this really isn't about Perl (yet). What follows is merely my attempt at understanding what's happening with the new Perl. Read the link above for the original Perl6 Exporter code. This node was getting long enough without my posting that code here.
From Apocalypse 1, if Perl6 sees a module or class declaration, it knows that it is Perl6 code. A package declaration means that we're dealing with Perl5 code.
This is pretty standard. Interestingly, the use strict might be superfluous here. According to the discussion regarding "lexical variables as default" in Apocalypse 4, use strict 'vars' will be the default in modules and classes. With Exporter, we're going to be turning off strict refs anyway, and the major effect of strict 'subs' is to inhibit Perl poetry ;) (please note that a semi-colon followed by a right paren is a 'wink'. That means it's a joke. Don't flame me ;) <-- see, that's another one ;)
Hoo boy, here's where I get bogged down. It looks to me like BrentDax is saying that we have an argument, $pkg, that has three adverbs. The first argument is the package of the module that inherits from Exporter, but what are the rest of the arugments? These are scalars that are references to particular types of data structures. Thus, when we see this:
It should mean that we have a scalar, that contains and array reference. Now, I'm not sure what the undef if for. I think this is to establish a default, which means that this is (I think) a typo. If so, it should read:
I don't think that interpretation is correct, however, as he properly uses the default operator in other places and thus understands its use. Now, as for how this all fits together, I'm not sure. The colon operator appears to be explained in Exegesis 3, page 6, under the heading "The ∑ of all our fears". I read and read and reread that section, but couldn't figure out what that meant in relation to the arg list in import(). Could someone please enlighten me?
Okay, that's pretty nifty. package is an attribute of caller (or is it a method that returns a value?). This is much easier to read then caller(0). I wonder, though, if we can adjust this to allow us to export to a lexical scope. There's been a fair amount of talk about a MY pseudo-package and having this accessible to caller. This could allow us to export something to a limited scope and not screw with the caller's symbol table! The following code is completely speculative, of course.
I have no idea what the actual syntax will be, but I wonder if some mechanism will be in place for a particular scope to protect the MY pseudo-package. It wouldn't be a lot of fun to call a poorly written function and have it, uh, barf all over your lexicals.
This is moderately straightforward. The pkg_alias() function takes two packages and makes the first and alais of the second. The next line is interesting, though. We are now aliasing (explained below) the myimport() function to the import() function, which is therefore aliased to whatever the calling packages import() function would be (I think). Since we have chained all of these together, doesn't this overwrite the calling packages import function, if any? On the other hand, why would we have an import function and then subclass Exporter? I suppose we could do this for some "special cases" that we might want to trap and then call Exporter::import (and assuming we can use something like goto to trick the call stack). The only thing I'm wondering about is whether or not beginning a function name with an ampersand and leaving off the parens will result in @_ being passed through (and aliased). Here's how the aliasing is accomplished. Let's jump ahead, though, and take a look at the pkg_alias function:
This looks fairly straightforward: alias one symbol table to another. Any subsequent changes made to one will affect the other. Aack! That looks like it's begging for trouble. Of course, now that we have lexical subs, we can have nice, tidy namespaces and this may not be as much of a concern. := This is the binding operator. It creates an alias from the rvalue to the lvalue. It's now used where we would have used typeglobs. The example above appears to be intended to alias the symbol table. Now, back to our regularly scheduled program. Rather than finish &import, we need to see what's happening in &myimport, or else the rest of the import function will not make any sense.
Aack! What the heck is that? The asterisk flattens the the arguments to a list and allows the array to slurp up the rest of the arguments, but I don't get this. Once again, any explanation would be helpful.
Nothing really interesting there, except for the default operator. As you might recall, Perl5 programmers would do something like this:
That has problems, though, if $foo has a valid value that evaluates as false (such as zero). Perl6's default operator says "if this value ain't defined", define with the rvalue. You can even chain these values:
Now things start to get strange again.
The single colon now has a lot of work to do, so the ternary operator (?:) is ambiguous. This will be corrected by changing the ternary operator to ??::. TheDamian argues that this is actually a better fit as the ternary operator short-circuits, just like && and ||. I understand what he's saying, but this just looks weird to me. Of course, a lot of Perl6 looks weird to me, so I should bite my tongue. Other than that, this is fairly clear. We map the @symbols array with the original value, if it doesn't start with a colon, or we grab the array of tags from the appropraite EXPORT_TAGS list.
Perl6 is supposed to allow for different module versions to be supported in the same program. So, if one of our symbols is just a number, then we know the module version that we're exporting from.
I think we have a typo here. The ternary operator should be ??::. At this point, since we're iterating over the symbols, we check to see if this symbol is a pair. If so, $to and $from are set the the left and right values (the key and the value?) of the pair, respectively. Otherwise, they are set to the current symbol.
If it's a bareword, they wanted to export a function, go prepend an ampersand. (?)
This is nice. We get a very clear error message if we're about to export over something that already exists. Also, note the interpolation of the object and it's method (attribute?): $(caller.file). This sort of DWIM interpolation should make life simpler in the future. <ocde> die("$exp_from doesn't export $from at $(caller.file) line $(caller.line).\n") unless grep {/^$from$/} @Exporter::From::EXPORT, @Exporter::From::EXPORT_OK; </code>Whoops! We tried to ask for something that isn't exported.
This is the actual export. Note that we're still in the symbol for loop.
I'll confess, I don't know what's going on here. I need to get home (well, actually, head to the pool league), so I need to cut this short. Rather than puzzle through this, I'll be lazy and say "If you understand this, please tell me". And to finish off the &import function:
Now, as I understand it, dereferencing will be a DWIM sort of thing. Thus, the type sigils on the right are not necessary.
There's no need to dereference anymore (except in unusual cases where the code is ambiguous) as Perl6 will do it for us. Well, that's about it. I need to run for the evening and I can't dig into this further, but I look forward to seeing any comments or thoughts people have. I'll also let you know how I did on my first night on a pool league :) Cheers, Update: I won the match :) Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.
Back to
Meditations
|
|