Re: Virtual methods
On Wed, 2005-05-25 at 09:11, Piers Cawley wrote: Aaron Sherman [EMAIL PROTECTED] writes: There are many gotchas that fall out of that. For example, you might have a special role that overrides .print to handle structured data, so your code says: my Foo $obj; given $obj { when StructuredPrintRole { # Someone's already taken care of it, possibly # adding a more specialized role, so leave it # alone. } default { # Add in a boring default handler $obj does StructuredPrintRole } } $obj.print($structured_data); Woefully, you lose [if] Foo happens to be DECLARED with StructuredPrintRole, and it overrode print. But, if it just inherited a print(), then it works. In other words, this code will mysteriously fail the second someone innocently adds a print method to Foo! Action at a distance... my head hurts. Aaron, you do realise that that's quite obscene code don't you? Why yes, I think that was my point. This is an unfortunate consequence of the proposed way of mixing in functionality. If this is not what mixins are intended for, then I guess I'm way out in the tall grass, as I'm nearly salivating over the potential. I mean, you're doing a case statement based on the type of its topic, And there's something wrong with switching on type? ... I'm sure I have no idea what's wrong with that. As long as smart matching does the right thing with inheritance (and S04 indicates that .does is invoked), this is a pretty traditional way to ask a variable if it does what you want. You could explicitly call the .can method, but as this example shows, you don't always want to know if the method EXISTS, but if it supports functionality that you need. and to compound the evils, you're changing how your topic's print method works *everywhere* simply to get your 'special' print behaviour. Yes, that is exactly the point. You have something that behaves like a filehandle, and you wish to tell it to handle structured data. You do this by first asking if it supports the appropriate interface (see S12 for how a role becomes an interface), and failing that, adding a default implementation. This probably looks something like: role StructuredPrintRole { has StructuredLayout $.sdlayout; method print($me: [EMAIL PROTECTED]) returns Int { $me.*SUPER::print(map:{ # A12 shorthand for WALK[:super]:: $_ ~~ StructuredData ?? $me.structure($me.sdlayout) :: $me; }, @list); } } So, by default you can .print to our $obj, and if you support some sort of structured data representation, the right thing happens (even though the normal stringification of such a value would not be the same). You might use this for, just as an example, protocol representation of an XImage datastructure for the X protocol. The stringification of it probably isn't the image data -- that wouldn't be terribly useful in general -- but for writing to an X socket, you certainly do want the data to be represented correctly, so you'd derive a role from StructuredPrintRole and tell it how to format X protocol data correctly. If you must do something like this (and call it print), then write it as a multimethod or something. I think you're thinking in terms of REPLACING functionality. I'm thinking in terms of AUGMENTING functionality. -- Aaron Sherman [EMAIL PROTECTED] Senior Systems Engineer and Toolsmith It's the sound of a satellite saying, 'get me down!' -Shriekback
Re: Virtual methods
Aaron Sherman [EMAIL PROTECTED] writes: On Wed, 2005-05-18 at 10:51, Luke Palmer wrote: Except that mixins like this always treat things as virtual. Whenever you mixin a role at runtime, Perl creates an empty, anonymous subclass of the current class and mixes the role in that class. Since roles beat superclasses, you'll always override your own methods. Ok, good point (I've even pointed that out to others before, and I missed it)... I know that's the way it works, but now it's really bothering me. There are many gotchas that fall out of that. For example, you might have a special role that overrides .print to handle structured data, so your code says: my Foo $obj; given $obj { when StructuredPrintRole { # Someone's already taken care of it, possibly # adding a more specialized role, so leave it # alone. } default { # Add in a boring default handler $obj does StructuredPrintRole } } $obj.print($structured_data); Woefully, you lose is Foo happens to be DECLARED with StructuredPrintRole, and it overrode print. But, if it just inherited a print(), then it works. In other words, this code will mysteriously fail the second someone innocently adds a print method to Foo! Action at a distance... my head hurts. Aaron, you do realise that that's quite obscene code don't you? I mean, you're doing a case statement based on the type of its topic, and to compound the evils, you're changing how your topic's print method works *everywhere* simply to get your 'special' print behaviour. If you must do something like this (and call it print), then write it as a multimethod or something.
Virtual methods
In Perl 6, I don't think we need to tag methods as virtual like C++ does, since we have the handy yadda, yadda to do that for us. However, there is a variant of C++'s virtual that I'd love to see. By default a role cannot override the methods of a class, but if it could override those methods specifically marked with the virtual trait, then we could define stub methods in classes that don't have a specific behavior until a more concrete role is mixed in. This gives you a form of auto-loading like delegation, but with less storage overhead (since there's no encapsulation until you need it). Here's an example: role X { has Str $.string handlesucfirst; # I'll write something like an accessor to avoid brining # up some questions around how virtual methods interact # with auto-accessors just yet. method setstring(Str $string) { $.string = $string } } class Y { method setstring(Y $me: Str $string) is virtual { $me does X; $me.setstring($string); } } my Y $var; $var.setstring(hello, world); # overrides setstring say $var.ucfirst; # says Hello, world $var.setstring(bye, now); # calls existing setstring say $var.ucfirst; # says Bye, now You can probably tell that I'm about to suggest that this would be the most efficient way to implement the dynamic functionality of Any, and given the recent ponie/parrot discussions around flags, I think using virtual methods as flags is probably the right way to go -- Aaron Sherman [EMAIL PROTECTED] Senior Systems Engineer and Toolsmith It's the sound of a satellite saying, 'get me down!' -Shriekback
Re: Virtual methods
On 5/18/05, Aaron Sherman [EMAIL PROTECTED] wrote: In Perl 6, I don't think we need to tag methods as virtual like C++ does, since we have the handy yadda, yadda to do that for us. However, there is a variant of C++'s virtual that I'd love to see. By default a role cannot override the methods of a class, but if it could override those methods specifically marked with the virtual trait, then we could define stub methods in classes that don't have a specific behavior until a more concrete role is mixed in. This gives you a form of auto-loading like delegation, but with less storage overhead (since there's no encapsulation until you need it). Here's an example: role X { has Str $.string handlesucfirst; # I'll write something like an accessor to avoid brining # up some questions around how virtual methods interact # with auto-accessors just yet. method setstring(Str $string) { $.string = $string } } class Y { method setstring(Y $me: Str $string) is virtual { $me does X; Except that mixins like this always treat things as virtual. Whenever you mixin a role at runtime, Perl creates an empty, anonymous subclass of the current class and mixes the role in that class. Since roles beat superclasses, you'll always override your own methods. Luke
Re: Virtual methods
On Wed, 2005-05-18 at 10:51, Luke Palmer wrote: Except that mixins like this always treat things as virtual. Whenever you mixin a role at runtime, Perl creates an empty, anonymous subclass of the current class and mixes the role in that class. Since roles beat superclasses, you'll always override your own methods. Ok, good point (I've even pointed that out to others before, and I missed it)... I know that's the way it works, but now it's really bothering me. There are many gotchas that fall out of that. For example, you might have a special role that overrides .print to handle structured data, so your code says: my Foo $obj; given $obj { when StructuredPrintRole { # Someone's already taken care of it, possibly # adding a more specialized role, so leave it # alone. } default { # Add in a boring default handler $obj does StructuredPrintRole } } $obj.print($structured_data); Woefully, you lose is Foo happens to be DECLARED with StructuredPrintRole, and it overrode print. But, if it just inherited a print(), then it works. In other words, this code will mysteriously fail the second someone innocently adds a print method to Foo! Action at a distance... my head hurts. -- Aaron Sherman [EMAIL PROTECTED] Senior Systems Engineer and Toolsmith It's the sound of a satellite saying, 'get me down!' -Shriekback