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)

Attachment: pgpTiSmZNGfT2.pgp
Description: PGP signature

Reply via email to