On Thu, 09 Mar 2017 07:39:39 -0800, elizabeth wrote:
> Yes, this is because classes / roles are not proper closures.  And
> yes, I’ve been bitten by this as well.
> 
It boils down to roles and classes being compile-time constructs, while 
closures are decidedly runtime ones. You can force a role to be re-evaluated 
each time by making it parametric, and passing the state as a role parameter. 
Note, however, that roles are interned based on the object identity of their 
positional parameters. This means the pattern, used on values, has a high 
chance of causing a memory "leak".

Note that the `but RoleName($value)` syntax that mixes in the role and, if it 
has a single attribute, assigns $value to it, is there to make cases like this 
a bit more convenient.

> To me, making them proper closures, feels like the correct solution to
> me. 
For this to happen we'd need:

* To clone the methods, attribute initialization closures, etc.
* To therefore have a cloned method table, Attribute objects, etc. to point to 
these clones
* Which implies a cloned meta-object
* Which in turn forces a new type table (which raises a bunch of questions 
about what .WHAT evaluates to)
* And the new type, formed per closed over set of values, will then miss on 
every single bit of our dynamic optimization infrastructure that keys on type 
(method caches, multi caches, specializations, etc.)

Declaring lexical classes and roles isn't an entirely unusual practice; without 
some careful analysis of when we need to do the cloning, we'd end up giving 
programs using this pattern a huge performance regression. All to give other 
programs a feature that will be hard to optimize, and so will then get a 
(deserved) reputation for being slow and thus probably not used all that much 
anyway.

> But I’ll settle for a warning / exceptione :-)

I think these options are worth consideration. I can't think of a false 
positive off hand.

/jnthn

Reply via email to