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