Re: Aliasing methods in CPAN roles

2009-10-19 Thread Raphael Descamps
Am Freitag, den 16.10.2009, 10:54 +0400 schrieb Richard Hainsworth:
 Arising out of Freezing Roles is a related question.
 
 Suppose I download a module from CPAN with a role I want to use, but it 
 introduces a method that I want that is in conflict with an existing 
 method (say one taken from another CPAN module).
 
 How should the method be aliased to prevent it from causing a conflict 
 at class composition time?

I personally don't anderstand why we don't have a exclude and alias
operator in Perl 6 but I have not read all the synopses and don't have
an overview.

In the thread Re: YAPC::EU and Perl 6 Roles in last july I already
said the following:
---snipp---
 The brilliant idea with traits is that it bring back the control to
 the class consuming the trait and conflicts have to be solved
 explicitly. The traits paper propose 3 different operators to solve
 such conflicts: overriding, excluding or aliasing.
 
 I definitively think that perl 6 roles should also have an excluding
 operator because I think that *every* composition conflicts arrising
 should be solvable by the class comsuming the role.
---snapp---

As a side note, Johnatan give us a example about how to make an alias
with user defined traits, but it doesn't help here because a trait is
bound to a definition:
http://use.perl.org/~JonathanWorthington/journal/39504
My anderstanding is also that that kind of aliasing as defined with a
trait is deep: If you alias a recursive method, the call will be done
to the aliased one (or am I wrong?).
In the original traits paper the aliasing is not deep: to respect the
flattening property, the semantic of the role must not change, so
aliasing a recursive method will call the original method. It's a known
theoretical weakness of the traits paper and freezing roles try to
solve this problem.

Finally, the interaction between module and role is also interesting and
it's not clear to me how Perl 6 solve it: I send a question this August
to the mailinglist but sadly had no reply, see Perl 6 modules and
classboxes?:
---snipp---
As Perl 6 will be supporting multiple versions installed of the same
module and also support import with lexical scoping, I was asking myself
if it was possible to combine some of the interresting properties of
classboxes like local rebinding, flattening property and the idea that
import takes precedence over inheritance.

I am absolutly not sure if it fit to the Perl 6 module concept as a
whole, but I will be happy to read your comments and what you think
about it.

A few pointers:

classboxes+traits introduction:
http://scg.unibe.ch/archive/papers/Berg05dTraitsClassbox.pdf

For an in depth description, you can also read the Ph.D. thesis:
http://scg.unibe.ch/archive/phd/bergel-phd.pdf

To develop the classbox concept, the autors also introduced a module
calculus, which also help to describe the difference existing beetween
different modules systems: (such a module calculus can also help to
better anderstand the interaction beetween different languages): 
http://scg.unibe.ch/archive/papers/Berg05cModuleDiversity.pdf
---snapp---

Raphael




r28846 - docs/Perl6/Spec

2009-10-19 Thread pugs-commits
Author: lwall
Date: 2009-10-19 19:20:38 +0200 (Mon, 19 Oct 2009)
New Revision: 28846

Modified:
   docs/Perl6/Spec/S12-objects.pod
Log:
[S12] treat all delegation objects equally including arrays and hashes


Modified: docs/Perl6/Spec/S12-objects.pod
===
--- docs/Perl6/Spec/S12-objects.pod 2009-10-19 16:22:20 UTC (rev 28845)
+++ docs/Perl6/Spec/S12-objects.pod 2009-10-19 17:20:38 UTC (rev 28846)
@@ -13,8 +13,8 @@
 
 Created: 27 Oct 2004
 
-Last Modified: 8 Oct 2009
-Version: 89
+Last Modified: 19 Oct 2009
+Version: 90
 
 =head1 Overview
 
@@ -1360,36 +1360,6 @@
 
 method select_tail handles wag hang {...}
 
-If your delegation object happens to be an array:
-
-has @handlers handles 'foo';
-
-then Perl 6 assumes that your array contains a list of potential
-handlers, and you just want to call the Ifirst one that succeeds.
-This is not considered a wildcard match unless the handles argument
-forces it to be.
-
-[Conjectural: the hash syntax is reserved until we figure out the
-semantics we really want, and whether this actually buys us anything
-over normal polymorphism.] If your delegation object happens to be
-a hash:
-
-has %objects handles 'foo';
-
-then the hash provides a mapping from a set of Selectors specified as Pair
-keys to the object specified as the Pair value that should be delegated to:
-
-has %barkers handles bark =
-(Chihauhau = $yip,
-Beagle = $yap,
-   Terrier = $arf,
- StBernard = $woof,
- * = $ruff,
-);
-
-If the current object matches no Selector, a Cnextsame is
-automatically performed.
-
 =head1 Types and Subtypes
 
 The type system of Perl consists of roles, classes, and subtypes.



Re: Aliasing methods in CPAN roles

2009-10-19 Thread David Green

On 2009-Oct-18, at 3:44 pm, Jon Lang wrote:

David Green wrote:

I would expect that   role Logging { method log(Numeric $x:) {...} }
means the invocant is really of type Numeric  Logging, without  
Logging having to do Numeric.  On the other hand, I can see that  
strictly that might not make sense, so perhaps I really do need to  
create a compound NumLog type first, so I can have method  
log(NumLog:)?

I think you should need to do this.


That's cumbersome, though.  I don't want to create some new type, that  
happens to do Numeric and Logging (in addition to other stuff it might  
do); I want to affect everything else that does both roles.  That is,  
I don't want my special log() method to work only for other types that  
explicitly do NumLog; I want it to work for any type that directly  
does Numeric does Logging.


In fact, I can already refer to that combination without needing to  
create a compound type; for example, in a signature I can say  
(Numeric Logging $x:).  I want my log() method to apply to $x there,  
even though it's Numeric Logging and not NumLog.


I don't like dangling methods outside of any role though, either.   
What I want to be able to do is say:

role Logging { method log(Numeric $x:) {...} }

and have it treat the invocant as something that does Logging  
(naturally, since it's part of the Logging role), and that also does  
Numeric (as specified in the sig).  It's too reasonable a thing to do  
not to have a reasonable way to express it.


Of course, I could do something like this:
role Logging
{
method log
{
given self
{
when Numeric {...}
when Stringy {...}
etc.
}
}
}

that is, I can do the dispatching myself.  But I shouldn't have to,  
especially in cases that are more complex than this simple example.



(But I'll suggest something new for - in general: what if $x -  
Numeric with no $n variable were shorthand for $x - Numeric $x  
is rw, i.e. a shorthand that used the same variable name inside  
the block as the one being passed in?  That would be useful in  
cases like this where we don't particularly want to rename $x.)


It wouldn't always be workable; for instance, @a - Numeric,  
Stringy { ... } would grab the first two element of @a and would put  
them into parameters; but there would be no obvious names to assign  
to those

parameters.


Yes, and I think it's OK for a shortcut like that to be available only  
in simple cases.



-David



Re: Aliasing methods in CPAN roles

2009-10-19 Thread Jon Lang
Raphael Descamps wrote:
 I personally don't understand why we don't have a exclude and alias
 operator in Perl 6 but I have not read all the synopses and don't have
 an overview.

I don't think that it's explicitly spelled out anywhere; but the
reason is fairly straightforward: exclude and alias would break the
interface.

Take Stringy as an example: when a class says does Stringy, it's
making certain promises about its syntax and semantics: e.g., it will
have a method say, and method say should result in sending a
string of text to an output stream.  Thus, any routine that asks for
Stringy $x as one of its parameters should be able to put $x.say
in its code and get the expected results.

But if Foo does Stringy but excludes or aliases .say, a routine that
asks for a Stringy $x but receives a Foo $x will run into problems the
moment $x.say shows up in its code.  If .say was excluded, the
semantics are no longer available at all.  If it was aliased, the
semantics are still available under another name; but that does the
routine no good, because it has no idea what the new name is, or even
that it exists.  Either way, $x.say will not do what the routine
intended it to do.  The interface is broken.

--
Jonathan Dataweaver Lang


unusual invocants

2009-10-19 Thread Jon Lang
In Aiasing methods in CPAN roles, David Green wrote:
 Jon Lang wrote:
 David Green wrote:

 I would expect that role Logging { method log(Numeric $x:) {...} }
 means the invocant is really of type Numeric  Logging, without Logging
 having to do Numeric.  On the other hand, I can see that strictly that might
 not make sense, so perhaps I really do need to create a compound NumLog type
 first, so I can have method log(NumLog:)?

 I think you should need to do this.

 That's cumbersome, though.  I don't want to create some new type, that
 happens to do Numeric and Logging (in addition to other stuff it might do);
 I want to affect everything else that does both roles.  That is, I don't
 want my special log() method to work only for other types that explicitly do
 NumLog; I want it to work for any type that directly does Numeric does
 Logging.

But if Logging doesn't do Numeric, why should it be expected to
provide a method that assumes that it does?

-- 
Jonathan Dataweaver Lang


Re: unusual invocants

2009-10-19 Thread David Green

On 2009-Oct-19, at 5:50 pm, Jon Lang wrote:

In Aiasing methods in CPAN roles, David Green wrote:
I don't want my special log() method to work only for other types  
that explicitly do NumLog; I want it to work for any type that  
directly does Numeric does Logging.


But if Logging doesn't do Numeric, why should it be expected to
provide a method that assumes that it does?


Well, I don't want all objects that do Logging to do Numeric; I just  
want to have custom methods for those that do happen to do both.


I could declare a sub log(Numeric Logging $x) that would work when its  
arg does both, but it has to be called like a sub, not a method.


If I can put ad hoc compound types into a signature, e.g. foo(Numeric  
Logging) instead of foo(NumLog), then why shouldn't it be possible to  
define a method that way?  Or conversely, should compound types in  
signatures be disallowed, and forced to use NumLog/whatever also?



-David



Re: Aliasing methods in CPAN roles

2009-10-19 Thread Jon Lang
Raphael Descamps wrote:
 In the original traits paper the aliasing is not deep: to respect the
 flattening property, the semantic of the role must not change, so
 aliasing a recursive method will call the original method. It's a known
 theoretical weakness of the traits paper and freezing roles try to
 solve this problem.

It's a problem that doesn't exist if you don't alias.  However, you
run into another problem; namely, what to do if two roles provide
semantically incompatible definitions for the same method.  To be
fair, ailasing doesn't solve the problem either, for the reasons that
I outlined in my last post (i.e., aliasing breaks the interface).  And
freezing roles doesn't solve the problem either; it just specifies
which role is broken in the combined interface.  As far as I can tell,
there are only two solutions that actually solve the problem: don't
compose two roles that have incompatible methods, or find a way for
the incompatible definitions to coexist under the same name.

The former approach works off of the theory that if the names are the
same, the semantics ought to be compatible; and thus incompatible
semantics are a sign of poor design of the base roles.  In an
environment where the programmer has the ability to rewrite everything
with which he's dealing, this makes a great deal of sense.  But as
Richard pointed out, CPAN is a counterexample to this: it is
unreasonable to assume that two modules imported from CPAN, written in
isolation by different authors, will never provide conflicting roles
due to nothing more than conflicting naming conventions - roles that,
in concept, ought to be able to be used together.

As I understand things, Richard's proposed solution is to alias one of
the offending methods during the import, effectively rewriting the
source module to use a different name for the offending method, for
the sole purpose of exporting to the target application.  IMHO, this
only works if you follow the chain of compositions all the way and
alias everything.  That is:

   role Foo { method x; }
   role Bar does Foo { method x; }
   role Baz does Foo { method x; }

If you want to alias Bar.x on import, there should be an implicit
aliasing of Foo.x as well, which would lead to the implicit aliasing
of Baz.x too.  It's the only way to avoid broken interfaces: you need
to change all related interfaces to remain compatible with the one
that you change, both up and down the composition chain.  Needless to
say, this strikes me as impractical, due to the effort involved in
figuring out what needs to be aliased and what doesn't.


Another possibility would be to borrow a page from XML Namespaces,
which addressed a similar problem: allow the programmer to require
imported elements to be referenced in terms of the module from which
they were imported.  E.g.:

use Kennel prefix Foo; # imports role Dog
use Forest prefix Bar; # imports role Tree
class Dogwood does Foo-Dog does Bar-Tree  { ... }
my $dogwood is Dogwood;
$dogwood.Foo-bark;
$dogwood.Bar-bark;

The idea here is that prefix Foo and prefix Bar cause every name
that gets imported from that module to be prefixed with that string.
So class Dogwood wouldn't have a bark method: it would have a
Foo-bark method and a Bar-bark method.  IOW, the above would be
equivalent to:

role Foo-Dog { ... method Foo-bark { ... } ... }
role Bar-Tree { ... method Bar-bark { ... } ... }
class Dogwood does Foo-Dog does Bar-Tree  { ... }
my $dogwood is Dogwood;
$dogwood.Foo-bark;
$dogwood.Bar-bark;

-- 
Jonathan Dataweaver Lang


Re: unusual invocants

2009-10-19 Thread Jon Lang
David Green wrote:
 Jon Lang wrote:
 In Aiasing methods in CPAN roles, David Green wrote:

 I don't want my special log() method to work only for other types that
 explicitly do NumLog; I want it to work for any type that directly does
 Numeric does Logging.

 But if Logging doesn't do Numeric, why should it be expected to
 provide a method that assumes that it does?

 Well, I don't want all objects that do Logging to do Numeric; I just want to
 have custom methods for those that do happen to do both.

...which strikes me as a perfect argument for putting those methods in
a role that does both.

 If I can put ad hoc compound types into a signature, e.g. foo(Numeric
 Logging) instead of foo(NumLog), then why shouldn't it be possible to define
 a method that way?  Or conversely, should compound types in signatures be
 disallowed, and forced to use NumLog/whatever also?

Because a method is part of a role, and ought to abide by the same
terms by which the role abides.  If Logging doesn't do Numeric, it
shouldn't have any methods in it that won't work unless it does.

-- 
Jonathan Dataweaver Lang