Help! I'm getting the error "invoke() not implemented in class 'Undef'" in my large application. What did I do wrong?
You've mistyped a class name which sits inside a namespace.
How am I supposed to figure that out?
I didn't say it was a particularly good error message.
It's like this: if you mistype a class name which is not in a namespace, you'll get an informative error message:
$ perl6 -e 'A.foo'
Could not find non-existent sub A
in Main (file src/gen_setting.pm, line 324)
However, if you mistype a class name which is in a namespace, you will get an uninformative error message:
$ perl6 -e 'A::B.foo'
invoke() not implemented in class 'Undef'
in Main (file <unknown>, line <unknown>)
So there's your error message. Linking it to the actual cause is something which you'll learn by experience.
So in that case, I don't get the name of the class which was mistyped in my program?
Correct.
And I don't get the line number of my typo?
Indeed not.
Or the file?
Right. You'll get no information about the location of the typo.
Is that intentional?
Well, no. As you see from the error message above, the information is meant to be printed, but it comes out as (file <unknown>, line <unknown>) instead.
Why?
Rakudo is built on top of Parrot. Usually, Rakudo generates its own error messages, but in some cases, Parrot will also generate an error. The error invoke() not implemented in class 'Undef' is such a case. When a Parrot-internal error like this one occurs, Rakudo will not be able to extract the annotation information required to provide a sensible line number and file.
I... I see.
Yeah. Sorry about that.
Are you able to pick up the irony in the fact that when I use namespaces to help mitigate the complexity of my project, I end up with an error message that in fact makes it harder for me to manage the complexity of my project?
Hold on.
Yes. We are able to pick up the irony in that. Quite easily, in fact.
Consider not using namespaces at the present juncture. They are very useful, but they are also known as a frequent source of annoyances like this.
By the way, I couldn't help but note that the line number and file information in your first example doesn't make any sense either. What the heck is src/gen_setting.pm and line 324?
Well, uh, that's the last line of internal Rakudo code that actually has a working line-and-file annotation. It's nothing that should reach the user, really.
So that's kinda broken, too?
Annotations are currently broken, yes. Apologies.
Back to my mistyped type name. My program is distributed over fifteen modules and ten thousand lines of code. How do you propose I find my typo?
First off, we recommend that you compile often. That way, the diff from the last working code will not be too large, and you will not have to visually scan so much text hunting for your typo.
Secondly, it's often useful to have your project in a version tracker such as Git, so that you can do git diff to see the changes against the index, or against the latest commit.
Thirdly, when all else fails, you can always insert print statements into your code, to try to bisect the origin of the error.
So in other words, Rakudo is no help whatsoever when this occurs?
Now, that's not quite fair. Rakudo tells you that the error occurs. That's actually useful information.
And you consider that adequate?
No, I didn't say that! No-one is happy about this situation. It's just the way things are.
So it can't be fixed?
Theoretically, yes. But not easily. Remember that the error occurs in Parrot.
Don't Rakudo and Parrot developers confer with each other?
Oh, sure we do. Do not assume that we're deliberately causing this situation. It's just that the current way Rakudo and Parrot are welded together makes the situation non-trivial to rectify.
So this problem is going to go away with the advent of the new ng branch?
There's nothing to indicate that this would be the case. In ng, you currently get a Null PMC access:
$
Null PMC access in invoke()
current instr.: '_block14' pc 29 (EVAL_1:0)
called from Sub '!UNIT_START' pc 984 (src/glue/run.pir:17)
called from Sub 'perl6;PCT;HLLCompiler;eval' pc -1 ((unknown file):-1)
called from Sub 'perl6;PCT;HLLCompiler;command_line' pc 1489 (src/PCT/HLLCompiler.pir:794)
called from Sub 'perl6;Perl6;Compiler;main' pc -1 ((unknown file):-1)
To its credit, Rakudo ng does provide more information in this case, but unfortunately the information is of a kind which was concealed from the user in Rakudo master about a year ago (because it tended to be very uninformative).
Just to summarize: this all sucks, right?
That would be a succinct description of the state of this particular error message, yes.
I heard that the Perl 6 community has adopted very high standards with respect to error messages. There's talk about "awesome error messages", and last summer I was in the audience when Larry Wall demonstrated how good Perl 6 was at reporting error messages to the user. How does this error message square with all of that?
The awesome error messages are like a platonic ideal towards which all implementations aspire. Rakudo, being rooted in our imperfect physical world, doesn't always get all the way. Yet.
I'm about to go visually scan ten thousand lines of code, looking for where my error message might have originated. Any last words?
We value your efforts as an early adopter of Rakudo. Your feedback is important to us. Have a nice day.
SF took my challenge to heart and started producing a "modern Perl 6" version of the example code in E02. His thought process can be seen here, and here.
After being a bystander for a few hours, I coulndn't restrain myself anymore: I produced my own version. I should say at once that it's quite different from SF's: while he keeps close to the original E02 (which, in turn, sets out to prove that Perl 6 is/was not very different from Perl 5), my version is a bit more liberal in its interpretation. I do mix in some of my personal preferences into it. Some examples:
$ARGS prompts("Search? ") anymore, but there's a nice &prompt function which I used instead, together with a while loop.&show function now uses gather/take, rather than printing directly.&show code.&show makes a point of using a slurpy @_ rather than naming the paramters. I don't. (Neither does SF.)given/when construct in the &insert function. To its credit, E02 tantalizingly hints of it, but then does a MIB mind-wipe. (You don't recall that bit? Oh well...)undef to initiate the child nodes to some empty value. Both SF and I independently realized that just any undefined value won't work if &insert is to have %tree in the signature, because %tree only binds to an Associative value. SF solved it by putting Hash (an undefined Hash type object) in the child nodes, and changed it to Hash.new in the later version. I used {}, which should be equivalent to Hash.new, but IMHO more idiomatic.I believe rewriting the exigeses in modern form is a very worthy activity. I hope we'll see more of that. Perl 6 suffers a bit from stale, outdated documentation, and having these in new versions would be valuable.
It's also a very interesting historical activity to read the old apocalypses and exigeses, as I increasingly find. Perl 6 has come a long, long way since 2001.
Not all of Perl 6 is Rakudo. Well, when I use Perl 6, it is. But I'm hoping 2010 will change that. We have a few other implementations out there, which fall in the "small but promising" category.
Mildew
From the README:
I can't say I've ever understood the idea behind naming projects after icky things, but I like the projects as such. They seem to generate a kind of "basic research" which strengthens the foundations of Perl 6. The decade-old project has always been about attacking the enormously big task of implementing Perl 6 from different angles — and I like the angle pmurias++ and ruoso++ are taking.
Mildew targets both SMOP (written mostly in C) and the Google V8 JavaScript compiler.
Sprixel
From the README:
I know diakopter++ is playing around with both JavaScript and C♯ implementations of Perl 6 rule engines. That is also an area which excites me, and where I'm glad people are making headway.
Vill
From the README:
Heh.
Whoa! That's potentially very attractive.
I'm actually hoping I might be able to help with the C-based parser.
Conclusion
Rakudo is the implementation that shows up on the radar of most outsiders right now. (And with good reason.) But much exciting work is going on in the background, with implementations like mildew, sprixel and vill.
I'm sure this will come off as almost self-evident, but I'll say it anyway: the moment an alternative implementation will cross a threshold into the area of the really interesting, is when it provides a significant chunk of Rakudo's functionality (which is saying quite a lot), together with some feature that Rakudo doesn't have. Given Rakudo/Parrot's current performance, the most obvious feature would be speed. But it might also be something else, such as a bridge to Perl 5, or a very solid metamodel. The more ground-shaking the new feature, the less important will be the delta between the alternative implementation and Rakudo.
At the very least, I think one of the above implementations will pass through the Mach 1 barrier in 2010, and attract a serious user base, and more developers. I'd love for Rakudo (and Pugs) to have some company up there among the "big" implementations.
Exciting times!
I don't know what kept me away from generating code for so long. Fear and prejudice, perhaps.
I've been trying it the last few days, and I have two things to say. First, it's like learning to program all over again. Remember that sense of power from the early days, when just picking up coding? "Hey, I can program this piece of code to do whatever I want." Well, guess what? That feeling comes back when one starts down on the path to madn... erm, to code generation. Only it's stronger. "Hey, I can program this piece of code to program that piece of code to do whatever it wants!" I think I've just discovered meta-hubris. Most likely, I'm not the first to do so.
Second, there's a flip-side to the feeling of power. That other feeling is how you feel when you knit your brows and wish that your neurons would line up a bit better so you could think more clearly about the problem at hand. Who would have thought, that feeling is also stronger when you're suddenly writing two different, entwined and related programs at the same time, in the same file. In my case, the knitted brows turn into an empty stare and a jaw left slackly agape, as I sit there wishing that I was better at context-switching between runloops.
Honestly, I think I expected eval to be the source of much programmer confusion, but I have to confess that it seems I underestimated the vistas it opens up when you buy into the idea of generating exactly the piece of code you need for the task (from an AST, say), and then eval it into a closure. That's what the back end of a compiler ends up doing, so maybe I shouldn't be so surprised that it's a versatile technique.
Lately, I've been in the business of squeezing every drop of juice out of the already implemented control flow constructs already implemented in Rakudo. I'm writing a p6regex→p6 compiler, you see. (Yes, that's a rather crazy notion; thanks for asking.) Along the way, I've often felt the need for not-yet-implemented control flow. This has led me to this hope-inducing maxim:
Every type of control flow in programming languages is just convenient sugar for if statements and while loops.
ifs and whiles are the stone soup to which all the rest of our control flow can be added as seasoning. ifs let you conditionally skip ahead in code, and whiles allow you to conditionally skip back. That's all you need.
Here are some examples.
if/elsif/else statements. Even Perl 6's given/when constructs.next, last and redo, either with or without a label to affect a less-than-innermost loop, can be desugared to sad boolean-ish variables, plus some if statements to appropriately regulate the expression of the code inside the loop. (Yes, go ahead and twitch just thinking of it. That sugar is there for a reason.)Aside from the switch statements and unlabeled next etc, which already work very well in Rakudo, I've been doing the whole list of desugarings in GGE (the regex compiler). The part with the continuations was especially fun. I needed them for backtracking, at least as long as the compiler was only an interpreter.
But then, during a fruitful discussion with diakopter++, I was told how to emulate (delimited) gotos with a switch and a loop. The idea is quite obvious in retrospect: just keep the current 'label' in a variable, and switch on it in each iteration. Presto! I should have thought of that. I don't even need to flee to PIR any more.
I took the idea and generalized it to delimited gosubs: instead of keeping the current label in a scalar, keep it at the top of a stack. Define macro-like constructs to push to (local-branch) and pop from (local-return) the stack. Suddenly I don't need continuations as much.
Result: this. We send in the regex/<[a..b]> | <[b..e]>/ on the top line, along with the target string c to match on. The program generates an AST, an anonymous subroutine which executes the regex in atomic Perl 6 operations, and finally a match object which indeed finds c to be a match.
Here's a similar but slightly more involved example. And here's one doing captures and backreferences inside a quantified non-capturing group. Isn't that exquisite? (Ok, bad choice of word. Sorry.)
As I said, I wrote most of with a feeling of being not just in over my head, but of being in over my head twice. I'm still a bit surprised it works. The runtime compilation seems to introduce a bit of a speed penalty, but (1) it's a one-time cost, since you can re-use the regex object, and (2) I told you it would be slow.
The code-generating work still resides only in a local branch on my computer. I'll push it to master as soon as I'm done bringing GGE back to its former capabilities. (Update 2010-01-24: Done, and done.)
Code writing code. What a concept!
The other day, I remembered this old piece of #perl6 backlog from 2005:
<masak> question: what are good ways in p5 and p6 respectively, to reverse a string?
<masak> the easiest way i found in p5 was join '', reverse split
<masak> doesn't look very nice, now does it?
<integral> *blink*
<integral> $string = reverse $string
It feels odd to realize this five years later, but it seems that in 2005 I didn't have a firm grip on how reverse worked in Perl 5. Chances are, dearest reader, that you do. But if not, the rest of the refreshingly frank discussion will explain it.
Meanwhile, five years earlier, I persist in my innocent ignorance:
<masak> nope
<masak> doesn't work
<masak> reverse only reverses lists... i think
Reading this from the perspective of five years' work with Perl 5 and 6 is... enlightening, in a slightly cathartic way. Sure, it could have been that I'm the first to discover that reverse in Perl 5 doesn't in fact reverse strings, despite thousands of people using it daily for that purpose. But the chances of that are astronomically small. My peers on the channel tell me this.
<PerlJam> masak: clearly you are insane.
<integral> perl -le '$string = "abc"; $string = reverse $string; print $string'
<integral> masak: the manual *clearly* explains all the stuff about context
<integral> and the faq
They do, you know.
<PerlJam> masak: in perl6 it would be $string.=reverse probably.
This was true in 2005, but nowadays we have flip for strings, reverse for lists, and invert for hashes. The need for different functions falls out naturally from the fact that Perl 6 doesn't depend as heavily on context as Perl 5 does.
Back in the log, I'm still trying to reintegrate into reality.
<masak> integral: your example worked, thx
<masak> but nothing worked for me
<masak> apparently i am insane
PerlJam and integral are one step ahead of me.
<integral> no, you don't understand scalar context. perl -le 'print scalar reverse shift' foobar
<PerlJam> masak: you were probably saying "print reverse $string"
<masak> no, but maybe something of the sort
<masak> and that doesn't work, because...?
<integral> masak: print's prototype is (@), ie list context. It's a rightwards named list operator
<PerlJam> masak: context.
* masak thinks he sees it now
These explanations are actually very good, but just in case, let me restate them in my own words: reverse has two main behaviours. Either it reverses a list of things, or it reverses a string of characters. It switches between these two behaviours based on something. You might think that this something is what type of thing you send in (a scalar or a list), but that isn't so. Instead, reverse responds to its surroundings and figure out what they expect. $string = reverse $string is a scalar assignment, and expects a scalar. print reverse $string, as integral explains, puts reverse in list context, so it reverses the list of one thing ($string), i.e. doing nothing.
Steve Yegge has this to say, in a vitriolic critique of Perl:
Perl also has "contexts", which means that you can't trust a single line of Perl code that you ever read.
I would say that it's actually not that bad, and the idea of context can be unintuitive at times, in many cases it's actually very natural and useful. reverse, in my humble opinion, is not one of those cases. I'm glad it's split up into different methods in Perl 6.
At the end, we learn that I had actually Read The Faithful Manual already, I just hadn't read it carefully:
<PerlJam> masak: perldoc -f reverse
<masak> thx, integral and PerlJam
<masak> PerlJam: I read the perldoc entry but apparently not carefully enough
* masak reads it again
<masak> ah
<masak> "In scalar context, concatenates the elements of LIST and returns a string value with all characters in the opposite order."
<masak> this somehow went past me as something i didn't want
In summary, I mostly wrote this blog post because I like to make myself squirm. 哈哈
But I guess there's also a moral to it all. We all start somewhere, and in a way it's reassuring to find five-year old proof of this fact. A newbie is just on a part of the learning curve you've already visited; they haven't had a chance to tweak their keyboard and developing environment to maximum efficiency yet, and they sometimes forget that the manual is there, or misread it in some way. So, don't hesitate to be be kind to them, and help them connect to the goodness that is perldoc, PerlMonks and Planet Iron Man so that they can grow and bloom into experienced wielders of Perl.
But don't hesitate to call them insane, either, when the situation calls for it.
A class hierarchy of expression nodes: it's so much the prototypical use case for run-time method polymorphism that it's almost a cliché. One can close one's eyes and picture the way parts of the expression tree interact in rich, complex ways, shaped by the very types of the nodes themselves, in a dynamic dance of late bindings and virtual methods. Switch statmement, get thee behind me. Et cetera.
I'm building one. And I'm having almost too much fun doing it. In between trying to use the strengths of Perl 6 and keeping true to the original program I'm porting, I've discovered an important thing: Ovid is right about roles.
Specifically, I'm having trouble picturing how I would cram all the type information into my expression node class hierarchy, were I not using roles. The roles definitely help manage complexity in my case.
Here's a pretty diagram of my class hierarchy.
It's a flat beast. Apart from everything deriving from Exp, I have only one case of old-skool inheritance in the diagram. And even that one is more making a point than actually shortening the code.
Then there's all the colorful dots, representing the roles I'm mixing into my types. Some are for convenience (like the blue ones), others are vital for my program (like the green ones), and the rest are somewhere in between on the convenient/vital scale.
I even have a case of inheritance between two of the roles! Which means, in practice, that those classes with an orange dot also act as if they had a red dot. Very handy.
During the infancy of Rakudo, I've gotten used to learning to live without various features. Were I to do what I'm doing here without using roles, I could use two other mechanisms. The first is regular inheritance. The very thought gives me a bit of vertigo; I don't think I'd be able to turn the colored dots into base classes. Definitely not all of them at once; I'd have to choose. And that choice would affect the entire design of the program, probably resulting in loss of clarity.
The second way I could compensate for not having roles would be by using.can a lot. The presence of a given role in a class is isomorphic to the presence of a given method in a class. So that would definitely work, but I don't think I would like it as much. There's something to be said for declaring is and does relationships at the very top of the class declaration.
All in all, I'm very happy about the way things work. I'm wondering whether, had I not read all of Ovid's posts on managing the complexity of class hierarchies with roles, I would have come up with this design myself. Maybe, maybe not. But anyway: thanks, Ovid! This rocks!
A still-open question for me is whether the topmost type, Exp, should be a class or a role. Synopsis 12 has this to say about when to use roles:
Classes are primarily for instance management, not code reuse. Consider using C when you simply want to factor out common code.
I am using Exp for code reuse, and for giving all of the other classes in the hierarchy a common base type. So I guess I could indeed turn it into a role. But it's just that... I don't see a reason to do so, and I still feel instinctively reluctant about it. Maybe I'm a bit hung up about it being a class hierarchy.
This point has come up before on IRC, and I've yet to hear a satisfactory way to resolve it: when faced with making a base type a class or a role, which way should one go?
Today I tested something that jnthn++ and I had discussed during a walk in the non-tourist parts of Riga after Baltic Perl Workshop.
$ cat test-goto
Q:PIR {
line_10:
};
say "OH HAI!";
Q:PIR {
goto line_10
}
$ perl6 test-goto
OH HAI!
OH HAI!
OH HAI!
OH HAI!
[...]
Oh. My. Wow.
The 1980's called; they want their infinitely looping toy BASIC idiom back.
I half-expected that not to work, but I'm glad it does. I can even
imagine it being of actual, code-simplifying use in some applications. The
reports of the harmfulness of GOTO have been greatly exaggerated, if you
ask me. Like everything else, the goto keyword shouldn't
be overused, but a well-placed goto LABEL can actually improve
readability. Often these masquerade as next LABEL or
last LABEL or redo LABEL in Perl loops. But those
are gotos with a nicer accent, a briefcase, and a better salary.
Unfortunately, the trick doesn't take us very far. Since we're using PIR
gotos, we can only jump around within the same sub. Not just
the same Perl 6 sub, that is, but the same PIR sub. Since every block in
Perl 6 corresponds to a sub in PIR, we can't jump outside of the block.
$ cat test-goto-loop
loop {
say "OH HAI!";
Q:PIR {
goto line_10
}
}
Q:PIR {
line_10:
};
$ perl6 test-goto-loop
e_pbc_emit: no label offset defined for 'line_10'
in Main (file <unknown>, line <unknown>)
Well, that certainly makes it less useful. Shame.
Now, how about them PIR-based continuations...? ☺
652 individual changes were made to the Perl 6 spec during 2009. I had a mind to read through them and make some sort of list of honorable mentions; unfortunately, that's not likely to happen in the next few days.
But I might as well mention why I got a sudden urge to list noteworthy changes: it's because in 99% of the cases, I like when the spec changes. A lively discussion in the last few days contained mentions of a proposed 'freezing' of the spec, in order to 'get there sooner' with Perl 6. I don't think freezing down the spec at this point would help us get there sooner. It would be if, say, most of the spec changes were ambitious semantic additions and new features. But most spec changes nowadays are responses to questions, complaints, comments and points of particular confusion from implementors, users, newbies or random people of Twitter.
Maybe I'll get around to summarizing the spec changes of 2009 later in January. Right now I'm having too much fun coding on a Perl 5/Perl 6 hybrid application.
A few days before Christmas, I was sitting in the car with my father. I decided to try to explain why I'm spending time doing Perl 6.
I compared the evolution of programming languages with the evolution of mathematical notation. In maths, it was tricky to imagine the concept of zero before it was formalized down to a number; the idea of derivatives was tossed around in vague forms before Newton and Leibniz made notations for it; we slowly but surely got a standard way of saying "is equal to". And so on.
I was just about to connect this back to how each new programming language can be seen as a contribution to an ongoing, open debate about notation within the programming world, one that has only been going on in earnest for half a century or so. But I never got that far, because my father interrupted me and asked what the business case is for Perl 6.
I was half stumped, half amused by this interjection. I didn't have a good answer for him, besides trying to explain FOSS and the fact that we're not developing Perl 6 with the expectation that someone will buy it from us. But I still felt he had a point; so, earlier today, I took the question to #perl6, and got a set of good replies and musings by Su-Shee++, moritz++, vorner++ and mdxi++. If you have time, do read it.
I'll have to give the 'business case' train-of-thought a lot more time to mature before I can say anything coherent about it myself. But I'd like to say a bit more about notations.
Perl 6 isn't truly revolutionary in a lot of respects. It's mostly lots and lots of minor improvements. (The exception being, I think, things surrounding grammars. Those are truly revolutionary.)
What Perl 6 does do, is provide a 'strangely consistent' notation where a lot of thoughts, with practice, are easy to express. This is very much in the Perl spirit, and the main reason (according to me) to still call Perl 6 a language in the Perl family.
The notational convenience really consists of a thousand little things, but here are a few haphazardly chosen examples:
?, + and ~ have been co-opted to signify conversion to the 'contexts' Bool, Num and Str, respectively. This parallels their use in binary (infix) operators specific to those contexts, such as +, ~, ?&, +&, and ~& is, has and does all do useful work in the OO system. Not only that, but they are a good fit for what they do, and summarize both established and modern OO research.(Bool $a, Int $b, Str $c) in my (Bool $a, Int $b, Str $c) = True, 42, 'foo'; is the same kind of beast as in sub foo(Bool $a, Int $b, Str $c) { ... }.) Smartmatching with ~~ is implicitly re-used in when expressions, and the given/when construct is re-used as the CATCH exception handling mechanism. And so on.It's things like these that I think make Perl 6 a convenient, attractive notation for thinking about programming. Seeing that notation come alive, and seeing people use it in cool new ways for amazing ends, is the main reason I spend time helping with Perl 6.
Sometimes wishes come true twice.
Many years ago, around the turn of the century, we wished for a revival in the Perl community; a rewrite. So we drafted up plans for Perl 6, a language which some unbiased commentators have described as 'quite ambitious'. While we were at it, we set out to refurbish the community.
Fast forward a few years, to circa 2004. Perl 5 had continued to be useful, but save for a
few CPAN modules in the Perl6:: namespace, nothing usable had
trickled back into the Perl community from the Perl 6 crowd. Some people got
tired of waiting. A revival/rewrite was still necessary.
So they made their own. It goes under a few different names, such as 'Perl Rennaisance', 'Modern Perl' or 'Enlightened Perl'. It has coding components, and people components. It's the community's rewrite of Perl, and the community's rewrite of the community.
The visual representation of the Perl story since year 2000 isn't linear; it looks like a tuning fork. A fork, that open-source term that people have learned to both love and hate. A divide, a split, a bifurcation.
And the strange thing is, no-one saw it coming. Both communities were so focused on their part, thinking that they were where Perl was going, that they didn't even notice the other side, across the gap. When inter-community contact was occasionally made, it easily got heated, for the simple reason that the realities weren't compatible anymore.
Well, now we're aware of it, and some of us realize that a war between Perl communities is wasteful, stupid and, you know, boring. So we're working on ways of not doing that. And we're kinda hoping, if you happen to belong to one of the communities, that you think it's a good idea.
Sometimes wishes come true twice. Instead of one true heir, we got two. Our natural impulses are to go for each other's throats. Slightly more difficult, but infinitely more enticing, is to find ways to rule the kingdom with twice as many resources, each language/community with her particular strengths.
I want to try that latter alternative.