Please don't assume that rakudo's idiosyncracies and design fossils are canonical. STD does better namespace management in some respects, particularly in accepting the approved predeclaration form:
class Foo {...} (and rakudo might now accept this too). You don't want to use augment for this, because augment is only for *cheating*, and will eventually require a 'use MONKEY_TYPING;' before it. You are correct that the one-pass parsing is non-negotiable; this is how humans think, even when dealing with unknown names. However, human language has ways of telling the listener whether a new word is a noun or a verb, and we generally choose not to require articles or verb markers in Perl 6, so class names (nouns) are officially ambiguous with function names (verbs). We could, as has been suggested before, have an optional noun marker for undeclared classes, but this tends to insidiously creep into lots of places, when a single predeclaration would be clearer and more efficient. The other reason we'll stick with one-pass parsing is that you can only do multiple pass parsing if you know exactly which language you're parsing all the time. This works against extensibility. Multiple passes introduce linguistic race conditions any time you're not sure what language you're in; see source filters for a good bad example of why you don't want to do multi-pass parsing. Because type names are nouns in Perl 6, we want to parse them like other nouns, such as variables and constants, not like verbs. Know whether something is a noun or a verb is very important in maintaining the two-terms-in-a-row prohibition, which is the primary way in which Perl 6 expressions are self-clocking. Break that clock and your error messages will turn to mush. Some of the smartest error messages that STD emits are actually the two-terms message transmogrified into something more specific by context. Therefore, a word that is declared as a sigilless noun must change the parsing from there on down so that we know to expect an infix after it, not a term, which a verb functioning as a listop would expect. constant Int pi = 3; pi 'foo'; # syntax error (Notice how the fact that Int is predeclared also allows us to correctly parse the constant declaration, since allows us to distinguish the existing type from the name to be declared.) Now that we have basic philosophy out of the way, on to other arguments. You might take the predeclaration policy as subtle encouragement to use the late binding provided by method calls, which don't require predeclaration. But Perl 6 is not religiosly OO to the exclusion of FP, so that's a weak argument, and we're not trying to discourage people from doing cross-module function calls. You make an analogy between type recursion and functional recursion, which is true up to a point, but types and other unsigilled names tend to be rarer than function names, so it makes sense, if we see an unknown name, to assume (if we choose to assume) that it is a postdeclared verb rather than a postdeclared noun. We don't want to break function recursion in order to support type recursion. We can't guess it both ways since we wouldn't know what to expect next. Perl 5 did lookahead and tried to guess in some cases, but this generally turned out to be a mistake. It was difficult to document and only inspired mistrust in the parser. Plus it degrades the two-term rule. But also note that there are several other ways to predeclare types implicitly. The 'use', 'require', and 'need' declarations all introduce a module name that is assumed to be a type name. We can also deduce that any use of Foo::Bar::baz to mean there exists a Foo::Bar type. STD does this already, though perhaps only as a lexically scope name at the moment. We might assume it to (at least potentially) be global. A 'use' also predeclares any types in its own space and makes the public ones available as predeclaration. From the standpoint of a typical midsized application that are spread across multiple files, most of the predeclarations should arrive like this, and not require a yadayada predeclaration. And in Perl 6 you shouldn't generally be using types without a 'use' of the definitions of those types, or you might not import some desirable multi into your lexical scope. Of course, we have to deal with 'use' cycles. Perl 5 simply assumes that it doesn't need to load a module that it knows is already being loaded, even if that loading is not complete or would result in something not being defined that ought to be. We could take the same agnostic approach and require the user to break use cycles explicitly with yada. Or we could detect that exact situation and relax the rules slightly to do a bit of dwimmery on type names that *start* with the partially compiled module. In that case, it might be reasonable, if we've got a suspended 'use Foo', to assume: Foo::Bar::baz # likely a function Foo::Bar::Baz # likely a class name and maybe even allow an assumed function to transmute into a known class if we guessed wrong, as long as they didn't try to use as a listop with args. Other heuristics are also possible. We could, in this case perhaps, relax the rule on multi-pass and take a preliminary grep of the suspended module for things that look like type or function declarations. Perhaps the user would choose a heuristic by pragma. But I also think that type recursion is likelier to indicate a design error than function recursion, so I'm not sure how far down this road we want to go. We could, for instance, create a new type name every time we see has Unknown::Name $.foo; that would eliminate most of the circularity problem for has-a relationships, at the expense of not catching typos till run time. Hard to know where to balance that. But in general, given that you ought to have used the appropriate definitions in the first place, I tend to bias in favor of catching typos no later than CATCH time. Hope this helps, or I just wasted a lot of time. :-) Larry