On Jul 24, 2005, at 2:40 AM, Sam Vilain wrote:
Stevan Little wrote:
Yes, we have. One thing to consider is that it is much easier to get the "Role order doesn't matter" thing when they are composed. Once you start keeping the roles around, you run into the possiblity for such things as "next METHOD" being executed in Role context. I wont even speculate on what that should/could/would do, because I think we just shouldn't go there.

We talked briefly about considering this "flattening" as being a
run-time state thing rather than necessarily taking place in the
Meta-objects.  Is this still tenable?

Well if the MetaClass is where all methods are stored, then it will need to be "meta" in some way. As for run-time vs. compile-time, that makes no difference. It happens at class composition time, which can take place at any (run|compile)time.

The strength of the role flattening is in the fact that, given it's rules of composition, it makes the order in which the roles are composed irrelevant. So as long as we flatten the same way, it does not matter.

My point was more that we need to keep the same flattening rules, and not let

Side effects like what happens if you do "higher level" stuff like run-time modification of Roles after they have been composed into classes can be addressed seperately.

Well, this was something I think we talked about. Basically my position is that once you compose a role into a class, the connection the class retains to that role is only minimal. Basically enough to handle "does" and nothing more. If you modify the Role at runtime, it will not affect and previous classes it was composed into.

Personally I don't like the idea of runtime class modification, I think it is a dangerous thing to do. But I understand that it is a useful feature in certain cases. But runtime Role modification I think is just insane, especially since roles can be used by multiple classes, and combined with multiple other roles. The combinations of conflicts and issues that can arise are endless. Not to mention the fact that given a widely enough used role, it would be practically impossible to reason about the affect of changing that role.

I think if you find that you need to modify your role at runtime, then you have actually found that you need a class, and not a role.

No, that's correct. We've just basically said that $.x is now a method
call, and as long as you stick to that invocation syntax it just has
to be declared as a method somewhere in the parentage/role-age of
this object.  But collisions in $.x declaration will be treated as
collisions in method declaration.
So we really are looking at closure based access to attributes. This also means that the idea behind P6Opaque as a storage format is very different. In theory, we could implement these style classes in a very "Inside-Out" manner. In a way, we could look at:
has $.x is rw;
as being sugar for this (pseudo) Perl 6:
    my %x;
    $?CLASS.meta.add_method('x' => method ($self: ?$value) {
        %x{$self.id} = $value if $value.defined;

Yes, precisely ... except the method returns a Proxy object.
The proxy object responds differently depending on its context.

Sure, that makes sense.

To summarise with code for those who are lost;

  has $.foo;

would be sugar for:

  has $foo;
  method foo is accessor( :FETCH { $foo },
                          :STORE -> $x { $foo = $x },

If you use \( $object.foo ) - that is, create a reference to the .foo property, you get a Proxy object; the above should be considered functionally equivalent to;

  has $foo;
  method foo is rw {
      return Proxy.new(:FETCH { $foo },
                       :STORE -> $x { $foo = $x },

This is looking a lot like properties in C#. Which look something like this:

private String node;
public String Node {
        get { return this.node; }
        # NOTE: the 'value' variable is created for you
        set { this.node = value; }

I think that is a good thing, I know I liked having properties when I did some C3 work a little while back.

This is extended into the other sigil types;

  has %.foo;

is sugar for this:

  has Hash $foo;   # or has %foo, but really, the point is it's
                   # an implementation detail, right?
  method foo is rw {
      return Proxy.new( :FETCH{ $foo },  # or a facade
                        :STORE -> Hash $x { $foo = $x },
        but {
            method post_circumfix:<{}>($key) is rw {
                return Proxy.new( :FETCH{ $foo{$key} },
                                  :STORE -> $x { $foo{$key} = $x },

I am not sure if it makes sense to handle whats inside the hash with the accessor. I think that is the responsibility of either the hash container type itself, or what you really need here is some kind of object to wrap your hash and get such fine grained control. But that is just my gut reaction.

Well, if we ditch the P6Opague type (as we currently know it) and use the Inside-Out method I show above. Then we just don't actually have class/instance attributes anymore at all. We really just have methods, some of which happen to be closures around per-instance values. Of course this means there is no direct access to attributes at all (which I think it not a bad thing, but I am into B&D like that).

So, if you want a "visitor pattern", you grab a visitor iterator
via the Meta-Objects, right? Which could also solve the STORABLE_freeze/STORABLE_thaw / Pixie::Complicity / etc problem by unifying the way that "foreign" objects can marshall themselves to Perl objects when required.

You mean for persistence operations? Where you need to thoroughly inspect the object to save it to disk/DB/etc.

I think the ideal way to write something like that would be to write is as a metaobject. Meaning using the Persistent metaclass. As opposed to using something on the "user" side of things to interogate the "meta" side of things. But this may be because I am too deep into the meta side if things right now.


*sniff* *sniff* this is smelling better and better :)

Sorry, I'll put that out.


Reply via email to