Re: S04 -- closure traits clarification

2005-05-02 Thread Larry Wall
On Fri, Apr 29, 2005 at 10:57:01AM -0500, David Christensen wrote:
: 1) What type of introspection, if any, are we providing to the language 
: level?  I.e., are we providing something along the lines of
: 
: %traits = ?BLOCK.traits
: 
: where %traits is keyed on trait name (FIRST, LAST, whatever) and in 
: turn is an array of closures?  This would mean, for instance that we 
: could say
: 
: ?BLOCK.traitsFIRST
: 
: to get the current block's FIRST closures, if any.

There is no .traits method.  Traits store their values into properties,
and properties are just mixins, and you get at the properties by calling
methods.  These particular traits push onto a correspondingly named
property, so you're probably looking for

$?BLOCK.firstlist

or some such.

: When parsing the 
: block for traits, coming across a new FIRST block would be akin to 
: saying:
: 
: push ?BLOCK.traitsFIRST, {...block contents...}
: 
: Specifically, I'm looking for definition of the syntax, which is only 
: alluded to in the Synopsis.

Probably does something like:

?BLOCK does First;  # no-op if it already does First
?BLOCK.firstlist.push(block);

: 2) If we accept the introspection at the block-level above, it seems 
: clear that we should also accept the same .traits method on variables.  
: I.e., in the above DBI example, we should get back the closure(s) for 
: undoing by referring to $sth.traitsUNDO.  Is a variable-level trait a 
: single entry, or can we have multiple will undo {...} predicates on a 
: single variable?  (The utility of such is left as an exercise to the 
: reader.)

The variable might not be aware that it has had such a trait applied
to it.  Remember that traits are allowed to cheat.  These traits need
only arrange to have block pushed onto the appropriate list after the
corresponding variable is successfully elaborated at run time, or otherwise
arrange not to run if their variable is not yet elaborated.  If this
information also shows up as metadata on the variable, that's probably
okay, but the implementation is unlikely to use that property directly.

Of course, a trait like constant would be expected to an effect on
the variable itself.

: 3) User-definable traits.  Now, this may be a closed domain of sorts, 
: but do we need to allow for the possibility of user-defined traits?  
: (I'm thinking here of variable-level will predicates.)  If so, do 
: user-defined traits get normalized to UPPER?  It would seem like we 
: would want consistency here, because if will undo {...} and UNDO 
: {...} get stored in the same trait slot, we're obviously transforming 
: one of the identifiers -- should this behavior be specific to our 
: built-in ones, or to all traits?

Already specced in A12.  As far as I know that part hasn't changed
significantly, but that could be because nobody's tried to implement
it yet.  :-)

: 4) Which of the closure traits are supported as will predicates on 
: variables?  Not all of the closure traits make sense on the 
: variable-level -- this information will be useful when trying to parse 
: the will predicates.

As Luke mentioned, will is just syntactic sugar for is.  A trait
is allowed to care about its semantics at compile time when you call
the trait handler, but this is totally transparent to the parser,
which will happily accept will qufklzuxfvklj {...}, turn it into
is qufklzuxfvklj({...}), and then fail to find an appropriate trait
handler in semantic analysis, or find some default trait handler that
scratches its head over qufklzuxfvklj before admitting defeat.

Or it may be that any trait that is unrecognized just gets applied as
a property of the variable.  But I think it's better if we treat
traits as declared items so that we catch typos, unless someone has
explicitly declared a autoloading trait handler.

Larry


Re: S04 -- closure traits clarification

2005-05-02 Thread Larry Wall
On Mon, May 02, 2005 at 03:20:03PM -0700, Larry Wall wrote:
: Probably does something like:
: 
: ?BLOCK does First;  # no-op if it already does First
: ?BLOCK.firstlist.push(block);

Probably shouldn't use up a normal name like First for that.  Maybe we
can just reuse the trait name as the role name

?BLOCK does FIRST;  # no-op if it already does First
?BLOCK.FIRST.push(block);

In this view, whether setting a trait clobbers an existing property or
merely appends to it depends on the trait handler's implementation.

I'm inclining more toward the view that all these blocks are pushed onto
the FIRST property at BEGIN time, but the will first properties are
wrapped in code that prevents them from running before their variable
is declared.  (Or maybe the wrapper just checks to see if the variable
is defined?  That would disable the block when you undef the variable.
That might be construed as a feature.)

Larry


Re: S04 -- closure traits clarification

2005-04-29 Thread Luke Palmer
David Christensen writes:
 Greetings,
 
 In trying to hack closure trait support into pugs, I have some 
 questions about closure traits, variable with will traits and 
 introspection.  (Apologies if some of this has been discussed on the 
 list before -- I'm just going off of the synopses, which if definite 
 clarification on some of these issues has been made, should probably be 
 updated to reflect the decisions made.)
 
 Firstly, it is suggested in S04 that variables indicated with a will
 predicate contribute to the corresponding block-level trait. 

Not really.  `will` is just defined as:

$a will foo {...}

Is the same as:

$a is foo({...})

So it's up to foo to associate itself with the block.

 I.e., if we have the following bit of code:
 
 if $dbh {
   my $sth will undo {$dbh.rollback} will keep {$dbh.commit} = FIRST 
 {$dbh.prepare($query)};
   UNDO {
   say DB error!;
   }
   KEEP {
   say We're good!;
   }
 }
 
 Then the block has in effect 5 total traits, 2 UNDO block, 2 KEEP 
 blocks and 1 FIRST blocks.  From what I understand, the blocks for each 
 trait are executed in FIFO order, thus we would rollback before we 
 report the error in this contrived example.

Nope.  Entry-time blocks are executed in declaration order.  Exit-time
blocks are executed in reverse declaration order.  Just like CHECK and
END in Perl 5.

 Questions:
 
 1) What type of introspection, if any, are we providing to the language 
 level?  I.e., are we providing something along the lines of
 
 %traits = ?BLOCK.traits
 
 where %traits is keyed on trait name (FIRST, LAST, whatever) and in 
 turn is an array of closures?  This would mean, for instance that we 
 could say
 
 ?BLOCK.traitsFIRST
 
 to get the current block's FIRST closures, if any.  When parsing the 
 block for traits, coming across a new FIRST block would be akin to 
 saying:
 
 push ?BLOCK.traitsFIRST, {...block contents...}
 
 Specifically, I'm looking for definition of the syntax, which is only 
 alluded to in the Synopsis.

What you are saying here seems reasonable.  However, we have to remember
that the closures are different for each run.  So the traits are not
associated with the block, but with the particular runtime instance of
the block.  Maybe that's what ?BLOCK refers to anyway.

I wonder how you could talk about the traits of a sub that isn't
currently executing.

 2) If we accept the introspection at the block-level above, it seems 
 clear that we should also accept the same .traits method on variables.  
 I.e., in the above DBI example, we should get back the closure(s) for 
 undoing by referring to $sth.traitsUNDO.  Is a variable-level trait a 
 single entry, or can we have multiple will undo {...} predicates on a 
 single variable?  (The utility of such is left as an exercise to the 
 reader.)

The question is, are you asking about the variable or the value?  For
instance:

my $block = ?BLOCK;  # _not_ calling
$block.traits;# variable traits or ?BLOCK traits?

We probably just use whatever the equivalent of `tied` is these days.
Let's call it, er, `tied`.

$block.traits; # ?BLOCK traits
(tied $block).traits;  # variable traits

 3) User-definable traits.  Now, this may be a closed domain of sorts,
 but do we need to allow for the possibility of user-defined traits?  

No.  By which I mean OF COURSE!

 (I'm thinking here of variable-level will predicates.)  If so, do 
 user-defined traits get normalized to UPPER?  

No.  Block level traits are different from variable traits, and they
should be declared separately.  The variable trait `undo` for instance
probably just pushes an UNDO handler on its caller.  Likewise, the UNDO
macro (?) does precisely the same thing.

But people are allowed to declare traits that are all caps, and block
handlers which are lowercase, and any combination of the above.  Perl
culture will try to enforce against that, however.

 It would seem like we would want consistency here, because if will
 undo {...} and UNDO {...} get stored in the same trait slot, we're
 obviously transforming one of the identifiers -- should this behavior
 be specific to our built-in ones, or to all traits?
 
 4) Which of the closure traits are supported as will predicates on 
 variables?  Not all of the closure traits make sense on the 
 variable-level -- this information will be useful when trying to parse 
 the will predicates.

Hmm, not quite sure.  Traits are a pretty big thing, and I'm not sure
what it buys you to hack them in.  I'd start by implementing the block
handlers without variable traits.

Luke