Re: Aliasing methods in CPAN roles

2009-10-20 Thread Raphael Descamps
Am Montag, den 19.10.2009, 16:43 -0700 schrieb 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.

You're of course right!

It's clearly explained in Apocalypse 12 (Conflict Resolution):
A role without implementation degenerates to an interface.

I don't know why but I didn't realised before that not implementing
exclude and alias was in fact an important design decision: I have
probably read to much traits papers and not enough Apocalyses ;)

On one side you lose flexibility to resolve some composition conflicts
but the fact that a role also define a contract is of course a big win,
particulary for a language like perl 6 supporting optional statical
typing. The traits paper only focus on dynamic typing.
It also explain why perl 6 as a so strong support for delegation, as it
is the proposed way to solve composition conflicts.

It's time to read Apacalyse 12 again as I am now able to anderstand
it :)



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




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


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: Aliasing methods in CPAN roles

2009-10-18 Thread David Green

On 2009-Oct-17, at 1:55 am, Jon Lang wrote:
This implies that both Logging and Math do Numeric, since the  
invocant ought to be of a type that the class does.


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:)?


Or can I create a method outside of any role:
role Numeric {...}
role Logging {...}
method log(Numeric Logging $x:) {...}

(of course, that might be implicitly creating an anonymous compound  
type for me...)



I think that what you're actually looking for (for the purpose of  
illustration) is Logging::log:(Numeric $x:) and Numeric::log: 
(Numeric $x:).


Oh, yes!

If $x does Numeric and $x does Logging, then it has a class that has  
already encountered the potential conflict and resolved it in some  
way.  For example:


   class Baz does Numeric does Logging {
   method log(Numeric $x:) {$x.Numeric::log;}
   method log(Logging $x:) {$x.Logging::log;}
   } #`Baz postpones the decision until it knows which role it's  
being asked to play: Numeric or Logging.


Baz illustrates my proposal: if $x is a Baz, it will need to check  
the context to see if it's supposed to be acting like a Numeric or  
like a Logging, and will act accordingly - or it will complain about  
ambiguity if it can't figure out which role to play.  And the  
definition for Baz works because Logging does Numeric.


I suppose given that I want Logging's method log(Numeric Logging:)  
rather than its log(Any Logging:), the second method there should  
really be:

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

You cannot define a class that does Logging and does Numeric without  
defining at least one log method, because they conflict; and a class  
must somehow resolve all such conflicts.


OK; although it seems reasonable to have some sugar for the obvious  
kind of keep them all methods like in this example.  In fact, we  
probably have that already, by declaring a proto log that makes the  
others all work according to their sigs.  And my mistake was thinking  
that you could have the same sig doing different things, but really  
the second sig is log(Numeric Logging:).


(The only way to have the same sig twice would be something like if  
Logging defined a special version of log() for Numeric objects, while  
Numeric defined a special log() for Logging objects -- but  
semantically that ought to mean the same thing in both cases, so we do  
want a single method to handle that.)


In the Baz case, it addresses the matter by making two options  
available according to the role being played: Numeric or Logging.   
All you have to do then is to somehow indicate which role is being  
played.


If you can't tell by the routine's signature, my own preference  
would be to make it explicit by means of a given block:


   given Logging $x { .log } # logs like a Logging
   given Numeric $x { .log } # logs like a Numeric


I also thought given sounded good for this, but it would have to  
work differently from a normal given: if $x doesn't do Logging, then  
it needs to skip the block.  (Also, it looks very close to casting:  
given Logging($x).  Maybe something a bit more visually distinctive  
would be helpful, something like given $x as Logging, etc.?)



But I could see other alternatives:
   .log given Logging $x; # assumes the inclusion of a given  
statement modifier.


I think given, as either a modifier or a block, is the prettiest  
syntax.



   $x - Numeric $n { ... ; $n.log ; ... }


What I like about this is using a sig to apply the context, so no new  
syntax is needed.


(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.)



   $x.log:(Logging:);



And I like this way because it's the most compact, inline way to  
indicate it.



-David



Re: Aliasing methods in CPAN roles

2009-10-18 Thread Jon Lang
David Green wrote:
 Jon Lang wrote:

 This implies that both Logging and Math do Numeric, since the invocant
 ought to be of a type that the class does.

 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.

 Or can I create a method outside of any role:
    role Numeric {...}
    role Logging {...}
    method log(Numeric Logging $x:) {...}

 (of course, that might be implicitly creating an anonymous compound type for
 me...)

Last I checked, all methods must be members of a class or role.

 I think that what you're actually looking for (for the purpose of
 illustration) is Logging::log:(Numeric $x:) and Numeric::log:(Numeric $x:).

 Oh, yes!

 If $x does Numeric and $x does Logging, then it has a class that has
 already encountered the potential conflict and resolved it in some way.  For
 example:

   class Baz does Numeric does Logging {
       method log(Numeric $x:) {$x.Numeric::log;}
       method log(Logging $x:) {$x.Logging::log;}
   } #`Baz postpones the decision until it knows which role it's being
 asked to play: Numeric or Logging.

 Baz illustrates my proposal: if $x is a Baz, it will need to check the
 context to see if it's supposed to be acting like a Numeric or like a
 Logging, and will act accordingly - or it will complain about ambiguity if
 it can't figure out which role to play.  And the definition for Baz works
 because Logging does Numeric.

 I suppose given that I want Logging's method log(Numeric Logging:) rather
 than its log(Any Logging:), the second method there should really be:
    method log(Numeric Logging $x:) {$x.Logging::log;}

I suppose that that would work, too.

 (The only way to have the same sig twice would be something like if Logging
 defined a special version of log() for Numeric objects, while Numeric
 defined a special log() for Logging objects -- but semantically that ought
 to mean the same thing in both cases, so we do want a single method to
 handle that.)

And if you limit yourself to referencing types that the method's role
does, this won't be an issue.

 If you can't tell by the routine's signature, my own preference would be
 to make it explicit by means of a given block:

   given Logging $x { .log } # logs like a Logging
   given Numeric $x { .log } # logs like a Numeric

 I also thought given sounded good for this, but it would have to work
 differently from a normal given: if $x doesn't do Logging, then it needs
 to skip the block.  (Also, it looks very close to casting: given
 Logging($x).  Maybe something a bit more visually distinctive would be
 helpful, something like given $x as Logging, etc.?)

IMHO, given $x { ... } is effectively syntactic sugar for $x - $_
{ ... }, and given Numeric $x { ... } would be syntactic sugar for
$x - Numeric $_ { ... }.  If $x doesn't do Numeric, the default
behavior should be a fail.

   $x - Numeric $n { ... ; $n.log ; ... }

 What I like about this is using a sig to apply the context, so no new syntax
 is needed.

 (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.

-- 
Jonathan Dataweaver Lang


Re: Aliasing methods in CPAN roles

2009-10-17 Thread Jon Lang
David Green wrote:
 Aha, so the bark:(Dog:) syntax identifies the method by its signature as
 well, thus distinguishing it from the .bark:(Tree:) method.  This works fine
 when the sigs can distinguish the invocants, which is very common.  However,
 I could have ambiguous methods even including the signatures.  Suppose I
 have a Logging role that provides a log() method for printing some info
 about a variable.  In particular, I have method log(Numeric $x:) { ... }
 because I want to handle Nums specially (say, round them off before
 printing).  Meanwhile, suppose I also have Math::log(Numeric $x:).

So you have Logging::log:(Numeric $x:), and you have
Math::log:(Numeric $x:).  This implies that both Logging and Math do
Numeric, since the invocant ought to be of a type that the class does.
 (And incidentally, this brings up another issue: as written, Math
isn't a class; it's a module.  Modules generally don't do roles,
assuming that they even can.)

Note further that in the setting, you actually have Math::log:(Numeric
$x).  Modules usually don't have methods, and so their routines
generally don't have invocants.

I think that what you're actually looking for (for the purpose of
illustration) is Logging::log:(Numeric $x:) and Numeric::log:(Numeric
$x:).  Continuing on with that:

 If $x does Numeric and does Logging, then $x.log won't be able to decide
 which method to call, unless maybe it's in a sub like foo(Numeric $x) that
 can know to provide Numeric context to $x.

If $x does Numeric and $x does Logging, then it has a class that has
already encountered the potential conflict and resolved it in some
way.  For example:

class Foo does Numeric does Logging {
method log(Numeric $x:) {$x.Numeric::log;}
} # Foo picks out the method from Numeric.

class Bar does Numeric does Logging {
method log(Numeric $x:) {$x.Logging::log;}
} # Bar picks out the method from Logging.

class Baz does Numeric does Logging {
method log(Numeric $x:) {$x.Numeric::log;}
method log(Logging $x:) {$x.Logging::log;}
} #`Baz postpones the decision until it knows which role it's
being asked to play: Numeric or Logging.

If $x is a Foo, then $x.log will always behave like Numeric::log; if
$x is a Bar, then $x.log will always behave like Logging::log.

Baz illustrates my proposal: if $x is a Baz, it will need to check the
context to see if it's supposed to be acting like a Numeric or like a
Logging, and will act accordingly - or it will complain about
ambiguity if it can't figure out which role to play.  And the
definition for Baz works because Logging does Numeric.

You cannot define a class that does Logging and does Numeric without
defining at least one log method, because they conflict; and a class
must somehow resolve all such conflicts.

 Outside foo, or inside a sub
 like bar(Any $x), I need some other way to indicate which log method I
 mean.  $x.log:(Numeric:) won't work here, because both roles provide a
 method with that name and signature.

As I indicated above, it will work, because $x.WHAT will have
addressed the matter already.  In the Foo and Bar cases, it addresses
the matter by picking one or the other and preventing access to the
one it doesn't pick; this is a viable stratagem if Logging and Numeric
are semantically similar (and, seeing as how Logging does Numeric,
they probably are).  In the Baz case, it addresses the matter by
making two options available according to the role being played:
Numeric or Logging.  All you have to do then is to somehow indicate
which role is being played.

If you can't tell by the routine's signature, my own preference would
be to make it explicit by means of a given block:

given Logging $x { .log } # logs like a Logging
given Numeric $x { .log } # logs like a Numeric

But I could see other alternatives:

.log given Logging $x; # assumes the inclusion of a given
statement modifier.
$x - Numeric $n { ... ; $n.log ; ... }
$x.log:(Logging:);

The point is that you're never going to have two different
log:(Numeric:) methods in the same class.

-- 
Jonathan Dataweaver Lang


Re: Aliasing methods in CPAN roles

2009-10-16 Thread David Green

On 2009-Oct-16, at 12:54 am, Richard Hainsworth wrote:
Is there syntactic sugar for aliasing the conflicting method? Eg.  
something like

does XML :db-writexml-db-write;


There needs to be something more than sugar: making a new class or  
role with different methods will break substitutability.  However, we  
could have a feature which aliases a method name in a given scope or  
context; elsewhere, the original name would still be visible.  So you  
could pass your new XML-plus-SQL object to do-xml-stuff(XML $x) and it  
would know to treat it as an XML object with the proper .db-write  
method.


(Incidentally, we could use something similar for renaming imported  
symbols, though in that case it would be only sugar.  Currently, we  
can choose to import something or not, but if a module exports  
something, it presumably has a good reason; rather than simply not  
importing the sub/etc., it would be handy to be able to import it  
under another name.


use Bar foo;# import Bar::foo
use Baz :fooboo;# import Baz::foo as boo()
use Baz foo='boo';   #  or spelled this way
)


Moreover, suppose that the two modules have roles with the same  
name, eg., suppose XML-Database-Module and SQL-Database both define  
a role 'Writable'. How could these one (or both) of these roles be  
aliased?



I suppose the polite thing would be for them to define roles (or  
anything else) inside their own namespaces: XML-Database- 
Module::Writable.



Meanwhile, on 2009-Oct-14, at 7:58 pm, Jon Lang wrote:
Another clarification: there's a subtle but important difference  
between $dogwood.bark:(Dog:).() and $dogwood.Dog::bark().  The  
former calls a Dogwood method that has an invocant that does Dog;  
the latter calls a Dog method.  That is:


   $dogwood.bark:(Dog:).(); # calls Dogwood::bark:(Dog:)
   $dogwood.Dog::bark();# calls Dog::bark:()


Aha, so the bark:(Dog:) syntax identifies the method by its signature  
as well, thus distinguishing it from the .bark:(Tree:) method.  This  
works fine when the sigs can distinguish the invocants, which is very  
common.  However, I could have ambiguous methods even including the  
signatures.  Suppose I have a Logging role that provides a log()  
method for printing some info about a variable.  In particular, I have  
method log(Numeric $x:) { ... } because I want to handle Nums  
specially (say, round them off before printing).  Meanwhile, suppose I  
also have Math::log(Numeric $x:).


If $x does Numeric and does Logging, then $x.log won't be able to  
decide which method to call, unless maybe it's in a sub like  
foo(Numeric $x) that can know to provide Numeric context to $x.   
Outside foo, or inside a sub like bar(Any $x), I need some other way  
to indicate which log method I mean.  $x.log:(Numeric:) won't work  
here, because both roles provide a method with that name and signature.


What if all roles' methods got automatic aliases, to a long(er) name,  
e.g. the .log method could be referred to as such, or  
as .Logging`log()?  That at least would provide a fully-qualified way  
to refer to methods no matter where they came from originally, and  
also allow short names to be used where unambiguous.


(I guess this parallels what we already have for subs, etc., except  
methods would be automatically exported into new roles or classes so  
that we can use short names.  I don't know what the actual syntax  
should be -- I only used ` above for lack of anything better, since  
the obvious .Logging::log means something else.)



-David