Re: Role Method Conflicts and Disambiguation

2005-10-29 Thread Yuval Kogman
On Fri, Oct 28, 2005 at 14:04:35 -0500, Jonathan Scott Duff wrote:

> That there will not be two slots for $:foo in Xy, but only one.
>
> But, I'm probably wrong about this as the X role may have methods that
> use $:foo in one way and the Y role may have methods that use $:foo in
> some other, incompatible way, so perhaps there will be a conflict just
> as when there are 2 methods of the same name.

Uh, that's horrible, because it means private attributes have only
the disadvantages of privacy (no access) and not the advantages
(separation, no conflicts).

non-private attributes should conflict, but private attributes are
no one's business except the package which made them.

-- 
 ()  Yuval Kogman <[EMAIL PROTECTED]> 0xEBD27418  perl hacker &
 /\  kung foo master: uhm, no, I think I'll sit this one out..: neeyah!



pgpGGuBWg08p4.pgp
Description: PGP signature


Re: Why submethods

2005-10-29 Thread Stevan Little

Luke,

On Oct 29, 2005, at 3:42 PM, Luke Palmer wrote:
Another thing that scares me with the "utility sub" point of view  
follows:


class Foo {
method process_data($data) {
$.help_process_data($data);
}
submethod help_process_data($data) {
$data+1;
}
}

Foo.new.process_data(0); # 1

class Bar is Foo { }

Bar.new.process_data(0); # dies[1]

What???  I didn't change anything yet!  Why does it die?  (This is the
first principle in the journal entry you quoted)


This is true, but I think that it is easily rectified. A submethod is  
said to have an implicit


  next METHOD unless $?SELF.class =:= $?CLASS

I think we could add onto that and say that in addition to checking  
the invocant's class, we could also check the calling context, and do  
like we do with private methods, and allow things like this to Just  
Work.


However, it could also be that the creator of Foo did not intend for  
subclasses to be able to "Just Work", and that the whole idea of Foo  
is to do a "Template Method" style pattern in which subclasses must  
implement the &help_process_data submethod in order for things to  
work. This is an entirely valid usage for a submethod, and in fact, I  
think it is an excellent way for implementing the "Template Method"  
pattern.


It is also possible that we could bring over the role idea of  
"required methods" and have the same basic principle relate to  
classes and submethods. If marked as such, a submethod is required to  
be implemented by a subclass, or class composition fails. I think  
that could be a useful feature which would allow very safe re-use  
along those lines.


Anyway, just my 2 cents.

Stevan



Re: Why submethods

2005-10-29 Thread Luke Palmer
On 10/29/05, Damian Conway <[EMAIL PROTECTED]> wrote:
> So we need a mechanism that is externally (i.e. from a class interface
> point-of-view) a subroutine, but internally has the features of a method (i.e.
> has an invocant). Since it's externally sub-like but internally method-like,
> we call this useful construct a submethod.

Hmm, thanks.

For most of that, doesn't a private method suffice?

When it doesn't, I feel uneasy about:

class Foo {
submethod bar() { ... }
}
my $foo = Foo.new;
$foo.bar;

If that's externally sub-like, why does it look so much like a method?

Another thing that scares me with the "utility sub" point of view follows:

class Foo {
method process_data($data) {
$.help_process_data($data);
}
submethod help_process_data($data) {
$data+1;
}
}

Foo.new.process_data(0); # 1

class Bar is Foo { }

Bar.new.process_data(0); # dies[1]

What???  I didn't change anything yet!  Why does it die?  (This is the
first principle in the journal entry you quoted)

Let's presume that I want to extend Foo by adding a method completely
unrelated to process_data, and I would like its behavior to stay the
same for process_data.  How would I do that?

Luke

[1] Well, it wouldn't, since for Liskov sanity we require that a
method of the same name already exists.  Let's say that Foo's parent
class implemented "submethod help_process_data($data) { die }".


Re: should roles be parameterized?

2005-10-29 Thread Luke Palmer
On 10/28/05, Christopher D. Malon <[EMAIL PROTECTED]> wrote:
> On Oct 28, 2005, at 11:13 PM, Luke Palmer wrote:
> Trying to think through the VectorSpace example, and a slightly
> more complicated example (a Field), I'm starting to wonder whether
> roles need to be parameterized somehow.  (Maybe they already are?
> This is one of my first p6 attempts, so bear with me...)

Oh yeah, roles can be parameterized.

role VectorSpace[Field ^f] {...}
role Field[AbelianGroup ^plus, Group ^times] {...}

I'm intentionally handwaving over some details that are important.  See below.

> role Group should define a method "inverse()" whose implementation
> is up to the class.  inverse(operation => '+') or inverse(operation
> => '*')
> would make perfect sense.  On an object that does Group only one way,
> inverse() by itself would be okay, but it would be ambiguous
> on a Field object.  I don't know whether it's better for the interpreter
> to produce a run-time error when a class implements a role in two ways
> and the parameter isn't supplied, or if one implementation of a role
> should
> take priority.

This is indeed the problem.  A related problem is, let's say you have
a utility sub for groups:

# Group $x meaining an element of a group... that's a little strange
sub power(Group $x, Int $pow) {
given $pow {
when $_ <  0  { power(inverse($x), -$pow) }
when $_ == 0  { identity() }
when $_ >  0  { $x * power($x, $pow - 1) }
}
}

But what if you have a set that is a group under addition?  That
doesn't work, since you're trying to multiply here.

sub power(Group[&infix:<*>] $x, Int $pow) {
# same body as before
}

That assumes that Group has one parameter: the operation under which
it is a group.  Then you *bind* that parameter to a lexical infix:<*>,
which means that when you say * within the body of your subroutine,
you actually mean whatever operation the group defines.

However, we still have a problem when we give a Field to power.  Which
group do we mean?  One way to do this would be to pass an optional
parameter: an object describing the group:

sub power(Group $x, Int $pow, GroupDesc $desc = $x.desc) {
given $pow {
when $_ <  0  { power($desc.inverse($x), -$pow, $desc) }
when $_ == 0  { $desc.identity }
when $_ >  0  { $x * $desc.power($x, $pow - 1, $desc) }
}
}

But that's starting to take away from the readability of the code, and
it really takes away from the fact that Group is encoding the
structure.

There was a proposal in Haskell to have what they called "named
instances", which addresses these kinds of problems:

http://www.informatik.uni-bonn.de/~ralf/hw2001/4.pdf

Perlizing the proposal, we might have something like:

role Field[&infix:<+>, &infix:<*>] {
does Group[&infix:<+>] FieldPlus;
does Group[&infix:<*>] FieldTimes;
...
}

power(4, 3) (FieldPlus);   # 12
power(4, 3) (FieldTimes);  # 256

All group operations on a field would be on the Plus group if we're in
a FieldPlus context, and conversely, all group operations on the field
would be on the Times group if we're in a FieldTimes context.

Exploring this issue further could be important to Perl's power when
it comes to automatic dispatch.

Luke


Why submethods

2005-10-29 Thread Damian Conway

In his use.perl.org journal, Luke wrote:

> To be fair, Damian responded to my query, but he didn't answer my
> question. He gave more an example of how submethods are used, rather
> than why they are used.

Subroutines are useful inside classes, for factoring class-specific 
implementation details out of the class's methods. The main reason they're 
useful is because they're not part of the object interface, and are not 
inherited. So they can be used purely for encapsulated implementation.


But factoring method implementations out into a subroutines is also extremely 
annoying, because a subroutine doesn't provide the internal conveniences that 
a method does. In particular, it doesn't have an invocant and so you can't 
call $.attrs or &.methods. Instead you would have to pass the invocant to the 
subroutine call as an argument and then call accessors and methods explicitly 
through that argument.


So we need a mechanism that is externally (i.e. from a class interface 
point-of-view) a subroutine, but internally has the features of a method (i.e. 
has an invocant). Since it's externally sub-like but internally method-like, 
we call this useful construct a submethod.


Damian