During the Pugs Hackathon at YAPC::NA 2005, I managed to get various unspecced tests and features reviewed by Larry, and posted them in my journal. The original notes is attached; I'd be very grateful if you or other p6l people can find tuits to work them back into the relevant Synopses. :-)
Thanks, /Autrijus/
* deref is now 0-level; $x = 3; $y = \$x; $y++. # now an exception * coercion is now done in mmd level in coerce:<as> calls. sqrt("element") now yields to 0. `my Int $x = "foo" as Str` casts. * `is lazy` parameters in MMD now causes the argument to be delayed even if other MMD candates mandate them as eager; it enters MMD not with the type of its evaluated result, but with its inferred type at compile time. * &prefix:<=> is just .shift in item context; in slurpy context it just the iterator into a generator. All arrays are concatenations of generators (which may or may not be preflattened) * &slurp() is the eager variant of list context &prefix:<=>; you can, alternately, use the steamroller &prefix:<**>. * my() declarations scopes lexically to the rest of the block; using `$MY::x` or `$::("x")` in the block before the actual declaration is erroneous. * Only Roles take type parameters. Hence, `Array` and `Hash` and `Scalar` are roles; PerlArray/PerlHash/PerlScalar are classes that conforms to them. A variable is bound to containers of the Perl* types by default, depending on its sigil. * Non-source-filter-ish macros work on the PIL(AST) level, not on parse tree level. The AST should preserve enough information to derive the original parse tree and source code back, for the compiler to use. * `return` inside blocks always throw out exception specific to its containing Routine; if the caller chain does not include that routine, it's just a fatal exception. * while foo() -> $_ {...} # binds $_ while foo() -> ?$_ {...} # does not bind $_ * sub foo (?$x, ?$Inf) {} my $y = (x => 3); foo($y); # binds $x my $z = (+Inf => 3); foo($z); # binds $Inf * The "Hash", "Int", "Str" etc are just roles: role Hash[?::returns=Any, ?::shape=Str] { } implementation classes are known as "PerlHash", "PerlInt" etc. * For pair/named binding to work, the inferencer needs to know it is a pair before putting it in the named binding position. sub foo ($x) { ... } sub bar returns Pair () { (x => 3) } my $y = (x => 3); foo({ x => 3 }.()); # This assigns (x=>3) to $x foo(bar()); # This assigns 3 to $x foo($y); # This assigns 3 to $x, too * `Parametric` type is now gone. `Bare` is merged with `Block` -- it's all of the `Block` type now. * Roles are also classes! They can be instantiated just fine if they are concrete enough. Basically they mean /composable classes/ or /mixin-able classes/. Hence, `RoleName.new()` instantiates an object that will probably fail on methods declared as stubs. * Class-defined methods with the same short name as their roles must conform to the same signature as the role methods; otherwise a fatal exception occurs. * Abstract pure methods in Roles really just return an Exception object, exactly the same way as if the `...` is evaluated normally. method foo () { ... } * Perl 6 is defined with separate compilation in mind; each compilation unit is going to pretend they are compiled in a different process. They are allowed to bind names (exports) in other namespaces, but they cannot read anything from others. * `&chomp` and `&wrap` are now nondestructive; chomp returns the chomped part, which can be defined by the filehandle that obtains the default string at the first place. To get destructive behaviour, use the `.=` form. * Filehandles opens chomped by default; you need to add the `:unchomped` flag to turn off chumping. my $fh = open 'file'; # autochomp my $fh = open 'file', :newlines; # non-autochomp $fh.newline = '\r'; # now split on \r $str = $fh.readline; $str.newline; # \r for chomp =$fh { ... } If .newline is a rule, then its captured variables are made available to the calling block as if it has done a matching. * The chained associativity level is associative with the precendence level it is in; hence, in the same level all chainfix operators glue together the same way the chained comparisons glue together. The listfix associativity always accept one trailing operator, so `1 Y 2 Y 3 Y` is legal. * Rules have their grammatical category, `&rule:<foo>`, that can reside in either grammars, non-grammar packages, or the true global namespace where they get names like `&*rule:<ident>`. Inside grammars they are called `&Foo::rule:<blah>`. * Grammar is a specialized form of Role (which is a special form of Class, which is a special form of Package). When a grammar `does` another grammar, it mixes in the grammar's rules as package globals. * To invoke an unqualified subrule, look at the lexical scope of the invocation site, then package globals, then finally global builtins. This is exactly the same order as a normal subroutine lookup. One can think rules as submethods that gets mixed in with a `does` call. You call them with the current invocant (i.e. the Grammar): # calling <ident> &rule:<ident>.($?SELF: $state); * To invoke a qualified subrule, one look the package-level named rule up, then invoke it with two parameters: The invocant is the package object that subrule belongs to; the argument is the state object the rule engine is currently treading upon: # calling <Grammar::ident> &Grammar::rule:<ident>($Grammar: $state); * To use a perl 5 module, put a `perl5:` in the front of the module name: use perl5:DBI; Extending this metaphor, to use a python module: use python:Zope; * When calling a function, the unary splat `*` takes an aggregate, or reference to an aggregate, and flatten them out on the invocation list. Unary splat on hash arguments flattens it out as pairs for named bindings; splat on scalars deref it to find an array/hash reference; for code and non-reference-to-aggreate scalars it's a no-op. * `&prefix:<int>` now always mean the same thing as `&int`. In the symbol table it's all stored in the "prefix" category; &int is just a short name way for looking it up -- it's just sugar, so you can't rebind it differently. * Here is a more clarified role hierarchy: Any | Object | Item | (pretty much everything else goes here) | Pair | Junction | int | str | num * Constrained types in MMD position, as well as value-based MMDs, are _not_ resolved in the type-distance phase, but compile into a huge given/when loop that accepts the first alternative. So this: multi sub foo (3) { ... } multi sub foo (2..10) { ... } really means: multi sub foo ($x where { $_ ~~ 3 }) { ... } multi sub foo ($x where { $_ ~~ 2..10 }) { ... } which compiles two different long names: # use introspection to get the constraints &foo<ANONTYPE_1> &foo<ANONTYPE_2> which really means this, which occurs after the type-based MMD tiebreaking phase: given $x { when 3 { &foo<ANONTYPE_1>.goto } when 2..10 { &foo<ANONTYPE_2>.goto } } in the type-based phase, any duplicates in MMD is rejected as ambiguous; but in the value-based phase, the first conforming one wins. * Closure composers like anonymous `sub`, `class` and `module` always trumps hash references: sub{...} module{...} class{...} * The `do` form is now taking a single statement instead of a block; what it does is turning the statement into an expression form, immediately evaluating it when the left hand side demands a value. my $val = do use CGI; # same as my $val = BEGIN { use CGI }; # This assigns 4 to $foo my $foo = do given 3 { when 3 { 4 } }; * A closure form of `but` is desugared into a `do given` block that eliminates the need of returning $_ explicitly. So those two forms are equivalent: my $foo = Cls.new but { .attr = 1; }; my $foo = do given Cls.new { .attr = 1; $_; }; * The anonymous class is allowed to both `is` and `does` any class/roles; it will be composed in compile time into an anonymous (but unique) class, same way as anonymous closures remember its original place of definition: role Foo {...} class Boo is Baz {...} (class{ does Foo; is Boo }).new(1); * The `is Foo` and `does Bar` statements inside class body is always lifted up as class traits and executed at class composition time. * There's another pseudopackage, `OUR::` and symbol table form `%OUR::` that contains the symbols in your current package namespace. * `trust` is lexical: It controls accessor generation for all `my`, `our` and `has` forms in its scope. Inside a class body, the `my $.x` and `our $.x` always generates public accessors on the spot: class Foo { trusts Bar; # sees the accessor methods in the scope { # some inner scope my $.x; # This creates accessors by inserting these two lines # die "Duplicate accessor" if %OUR::<&x>; # our &x := method () is rw { $.x }; my $:y; # This create accessors by inserting these two lines # my &:y := method () is rw { $:y }; # $?SELF.trust_access.push(&:y); # adds to Bar -- $?SELF is class object } trusts Baz; # this is always an no-op because there's nothing below } class Pie is Foo { } Pie.x = 5; # lvalue method - writes back to lexical $.x say Bar.x; # 5 - shared by Bar and Pie The twigil `.` and `:` controls the generated accessor's scope (`our` and `my` respectively). The scope of the variable itself is orthogonal to the accessor. * In order to pass by read-only reference, we need a way to bind a container into a new name, but say that it is read-only while the original is read-write. This is a contradiction, since binding by definition binds a container to two names. Still, we have to do it. In parameter lists, the `is constant` default trait on parameter variables is not really acting on their containers; it creates a transparent container on top of an existing container. It is "transparent" because it autoderef for everything except for write-type STORE/PUSH/SPLICE methods; all read methods like FETCH are passed to the underlying container. Even `.ref` and `.does` calls are passed through to the underlying container, but the `.tied` call does get you the wrapped implementation object. The upshot is that these are now errors: sub foo ($x) is rw { $x } my $a; foo($a) = 4; # runtime error - assign to constant sub constref ($x) { \$x } my $a; my $r = constref($a); $$r = 4; # runtime error - assign to constant To get a normal reference, use the `is rw` trait on the parameters. * `$OUTER::x` now means whatever `$x` is visible in the immediate outer scope, unlike `$MY::x` which is strictly this lexical scope. `$CALLER::x` similarily means whatever `$x` is visible in the immediate caller scope. Same applies exactly to the pseudopackages. * `tied` is still spelled `tied` in Perl 6; it always return the implementation object of the variable's container, instead of `undef` for the builtin types. * To evaluate in caller's lexical context: ::CALLER.meta.eval('xxx'); (this syntax is not canonical yet)
pgpTiSmZNGfT2.pgp
Description: PGP signature