Re: Virtual methods

2005-05-26 Thread Aaron Sherman
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

2005-05-25 Thread Piers Cawley
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

2005-05-18 Thread Aaron Sherman
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

2005-05-18 Thread Luke Palmer
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

2005-05-18 Thread Aaron Sherman
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