Re: Are proposals for new language methods considered?
The language is intended to evolve; the specification will change as we go. If you have a proposal, go ahead and make it, see what traction it gets on the list. On Sun, Jan 31, 2016 at 8:27 AM, Tom Browder <tom.brow...@gmail.com> wrote: > I would like to propose some new Str and IO::Path methods if such > would be considered. > > Best regards, > > -Tom -- Will "Coke" Coleda
Re: Are proposals for new language methods considered?
On Sun, Jan 31, 2016 at 5:01 PM, Will Coledawrote: > The language is intended to evolve; the specification will change as we go. > > If you have a proposal, go ahead and make it, see what traction it > gets on the list. Is there any specific format for a proposal? If not, is there a successful example available for reference? Thanks, Will. Best, -Tom
Re: Are proposals for new language methods considered?
Nope. Most people just show up on #perl6 and chat, or make a pull request or open an RT. On Sun, Jan 31, 2016 at 6:10 PM, Tom Browderwrote: > On Sun, Jan 31, 2016 at 5:01 PM, Will Coleda wrote: >> The language is intended to evolve; the specification will change as we go. >> >> If you have a proposal, go ahead and make it, see what traction it >> gets on the list. > > Is there any specific format for a proposal? If not, is there a > successful example available for reference? > > Thanks, Will. > > Best, > > -Tom -- Will "Coke" Coleda
Re: Are proposals for new language methods considered?
On Sun, Jan 31, 2016 at 5:20 PM, Will Coledawrote: > Nope. Most people just show up on #perl6 and chat, or make a pull > request or open an RT. Gotcha, thanks. -Tom
Are proposals for new language methods considered?
I would like to propose some new Str and IO::Path methods if such would be considered. Best regards, -Tom
[perl6/specs] beb870: Spec action objects/methods
Branch: refs/heads/master Home: https://github.com/perl6/specs Commit: beb870dbff3460b981055034ee5b6e72307b7d34 https://github.com/perl6/specs/commit/beb870dbff3460b981055034ee5b6e72307b7d34 Author: Rob Hoelz r...@hoelz.ro Date: 2015-07-04 (Sat, 04 Jul 2015) Changed paths: M S05-regex.pod Log Message: --- Spec action objects/methods Commit: e4f79178aa87db3fd51ca50eeb38451c86cc7b42 https://github.com/perl6/specs/commit/e4f79178aa87db3fd51ca50eeb38451c86cc7b42 Author: Rob Hoelz r...@hoelz.ro Date: 2015-07-04 (Sat, 04 Jul 2015) Changed paths: M S99-glossary.pod Log Message: --- Link to action objects section in glossary Compare: https://github.com/perl6/specs/compare/ace089e004fe...e4f79178aa87
[perl6/specs] 66d345: Detail action methods + dynvar behavior
Branch: refs/heads/master Home: https://github.com/perl6/specs Commit: 66d345c46eb3e16bdb2f3257bb2265bb803f610c https://github.com/perl6/specs/commit/66d345c46eb3e16bdb2f3257bb2265bb803f610c Author: Rob Hoelz r...@hoelz.ro Date: 2015-07-05 (Sun, 05 Jul 2015) Changed paths: M S05-regex.pod Log Message: --- Detail action methods + dynvar behavior
[perl6/specs] 5a57b9: Add blurb about symlink (lstat) methods
Branch: refs/heads/newio Home: https://github.com/perl6/specs Commit: 5a57b95040c9581e63cc51c4b682365e67a94bcb https://github.com/perl6/specs/commit/5a57b95040c9581e63cc51c4b682365e67a94bcb Author: Elizabeth Mattijsen l...@dijkmat.nl Date: 2015-02-12 (Thu, 12 Feb 2015) Changed paths: M S16-io.pod Log Message: --- Add blurb about symlink (lstat) methods
[perl6/specs] f07639: Don't use accessor methods in their own implementa...
Branch: refs/heads/master Home: https://github.com/perl6/specs Commit: f0763966964429f9bb835783635f97d6a3423c31 https://github.com/perl6/specs/commit/f0763966964429f9bb835783635f97d6a3423c31 Author: Rob Hoelz r...@hoelz.ro Date: 2015-01-15 (Thu, 15 Jan 2015) Changed paths: M S05-regex.pod Log Message: --- Don't use accessor methods in their own implementation name should not be defined in terms of name with no terminating condition
[perl6/specs] 1a4d94: Change Range excludes_* methods to dashes
Branch: refs/heads/master Home: https://github.com/perl6/specs Commit: 1a4d949358408eb3e7b5a7461264f4f356c8eeb9 https://github.com/perl6/specs/commit/1a4d949358408eb3e7b5a7461264f4f356c8eeb9 Author: Lucas Buchala lucasbuch...@gmail.com Date: 2014-11-25 (Tue, 25 Nov 2014) Changed paths: M S03-operators.pod M S32-setting-library/Containers.pod Log Message: --- Change Range excludes_* methods to dashes Commit: b983b23af7be05288ffa0c2d9a553e7dd6735665 https://github.com/perl6/specs/commit/b983b23af7be05288ffa0c2d9a553e7dd6735665 Author: Moritz Lenz mor...@faui2k3.org Date: 2015-01-01 (Thu, 01 Jan 2015) Changed paths: M S03-operators.pod M S32-setting-library/Containers.pod Log Message: --- Merge pull request #74 from lucasbuchala/range-excludes Change Range excludes_* methods to dashes Compare: https://github.com/perl6/specs/compare/8969a7418661...b983b23af7be
[perl6/specs] a80149: Hint a bit at is export for methods
Branch: refs/heads/master Home: https://github.com/perl6/specs Commit: a8014958d3f4ebb5c02cb4c840fea487ce788a0b https://github.com/perl6/specs/commit/a8014958d3f4ebb5c02cb4c840fea487ce788a0b Author: Elizabeth Mattijsen l...@dijkmat.nl Date: 2014-08-11 (Mon, 11 Aug 2014) Changed paths: M S11-modules.pod Log Message: --- Hint a bit at is export for methods Commit: ce07358d1a24f48837c616e9606d00ac03291036 https://github.com/perl6/specs/commit/ce07358d1a24f48837c616e9606d00ac03291036 Author: Elizabeth Mattijsen l...@dijkmat.nl Date: 2014-08-11 (Mon, 11 Aug 2014) Changed paths: M S29-functions.pod Log Message: --- Some cleanup/additions to S29 Compare: https://github.com/perl6/specs/compare/aa6f2438d000...ce07358d1a24
[perl6/specs] b3fceb: lock() is now Lock.new and its methods
Branch: refs/heads/master Home: https://github.com/perl6/specs Commit: b3fceb8cf355d008ef29df432c60438aee6bf3d6 https://github.com/perl6/specs/commit/b3fceb8cf355d008ef29df432c60438aee6bf3d6 Author: Elizabeth Mattijsen l...@dijkmat.nl Date: 2014-08-11 (Mon, 11 Aug 2014) Changed paths: M S29-functions.pod Log Message: --- lock() is now Lock.new and its methods
[perl6/specs] f017ef: Further refinement on IO.x methods
Branch: refs/heads/master Home: https://github.com/perl6/specs Commit: f017efdf4b971510b64beffc9d0086583b28943a https://github.com/perl6/specs/commit/f017efdf4b971510b64beffc9d0086583b28943a Author: Elizabeth Mattijsen l...@dijkmat.nl Date: 2014-05-26 (Mon, 26 May 2014) Changed paths: M S32-setting-library/IO.pod Log Message: --- Further refinement on IO.x methods
[perl6/specs] f4b120: [S15] Replace .compose/.decompose methods.
Branch: refs/heads/master Home: https://github.com/perl6/specs Commit: f4b12007dbcae35464a0e9fa3497c1f48c0b85b0 https://github.com/perl6/specs/commit/f4b12007dbcae35464a0e9fa3497c1f48c0b85b0 Author: lue rnd...@gmail.com Date: 2013-12-13 (Fri, 13 Dec 2013) Changed paths: M S15-unicode.pod Log Message: --- [S15] Replace .compose/.decompose methods. Left behind from the move to multiple string types. Commit: e020cb1303504cc8902aec7c834601b2afab868c https://github.com/perl6/specs/commit/e020cb1303504cc8902aec7c834601b2afab868c Author: lue rnd...@gmail.com Date: 2013-12-13 (Fri, 13 Dec 2013) Changed paths: M S15-unicode.pod Log Message: --- [S15] Fix ord(s) to work on all Stringy. This presumes that Unicodey does Stringy. If not, then you simply need to add the signatures for Unicodey things where these changes were made. Additionally, some clarification on .chr(s). Compare: https://github.com/perl6/specs/compare/9c555ea63fe0...e020cb130350
[perl6/specs] 8f30d2: nodal ok on normal methods too, not just protos
Branch: refs/heads/master Home: https://github.com/perl6/specs Commit: 8f30d2d1ebdf4c96f1f110bad0e0884f613811f8 https://github.com/perl6/specs/commit/8f30d2d1ebdf4c96f1f110bad0e0884f613811f8 Author: Larry Wall la...@wall.org Date: 2013-07-13 (Sat, 13 Jul 2013) Changed paths: M S03-operators.pod Log Message: --- nodal ok on normal methods too, not just protos
[perl6/specs] 415f99: Add IO::Handle methods encoding and open (really!)...
Branch: refs/heads/master Home: https://github.com/perl6/specs Commit: 415f998968a441cd2b58f85c0007814a5d7c05dd https://github.com/perl6/specs/commit/415f998968a441cd2b58f85c0007814a5d7c05dd Author: labster bsla...@gmail.com Date: 2013-05-27 (Mon, 27 May 2013) Changed paths: M S32-setting-library/IO.pod Log Message: --- Add IO::Handle methods encoding and open (really!), cleanup slurp Minor cleanup in IO::Spec. TODO: Pipes
[perl6/specs] 696068: Change IO::Path stringification, add new methods.
Branch: refs/heads/master Home: https://github.com/perl6/specs Commit: 696068389ab2e29cd0f85a136350fee614acf379 https://github.com/perl6/specs/commit/696068389ab2e29cd0f85a136350fee614acf379 Author: Brent Laabs bsla...@gmail.com Date: 2013-03-28 (Thu, 28 Mar 2013) Changed paths: M S32-setting-library/IO.pod Log Message: --- Change IO::Path stringification, add new methods. .Str returns full path instead of basename .path is now a no-op (so Str.path.path still returns IO::Path) .contents is now documented - lists the directory .is-absolute, .is-relative, .absolute, .relative added
[perl6/specs] 09c9f5: [S32::Exception] mention methods resumable and res...
Branch: refs/heads/io-refactor Home: https://github.com/perl6/specs Commit: 09c9f53eaf763ee58508641e4758fa764743b22f https://github.com/perl6/specs/commit/09c9f53eaf763ee58508641e4758fa764743b22f Author: Moritz Lenz mor...@faui2k3.org Date: 2012-07-12 (Thu, 12 Jul 2012) Changed paths: M S32-setting-library/Exception.pod Log Message: --- [S32::Exception] mention methods resumable and resume
[perl6/specs] 953a85: [S32::IO] all .read methods should return a Buf. T...
Branch: refs/heads/master Home: https://github.com/perl6/specs Commit: 953a85bcfbb8a22aaac883268cfc5ce03bdcdcc0 https://github.com/perl6/specs/commit/953a85bcfbb8a22aaac883268cfc5ce03bdcdcc0 Author: Moritz Lenz mor...@faui2k3.org Date: 2011-09-23 (Fri, 23 Sep 2011) Changed paths: M S32-setting-library/IO.pod Log Message: --- [S32::IO] all .read methods should return a Buf. This is not C.
r32013 -[S02] spec which methods Nil responds to,
Author: lwall Date: 2010-08-16 19:49:53 +0200 (Mon, 16 Aug 2010) New Revision: 32013 Modified: docs/Perl6/Spec/S02-bits.pod Log: [S02] spec which methods Nil responds to, and that it propagates Nil on unrecognized methods Modified: docs/Perl6/Spec/S02-bits.pod === --- docs/Perl6/Spec/S02-bits.pod2010-08-16 14:30:39 UTC (rev 32012) +++ docs/Perl6/Spec/S02-bits.pod2010-08-16 17:49:53 UTC (rev 32013) @@ -14,7 +14,7 @@ Created: 10 Aug 2004 Last Modified: 16 Aug 2010 -Version: 221 +Version: 222 This document summarizes Apocalypse 2, which covers small-scale lexical items and typological issues. (These Synopses also contain @@ -2153,14 +2153,23 @@ you can think of Perl 5 references as a degenerate form of CCapture when you want to refer only to a single item. -There is a special CParcel value named CNil. It means there is no -value here. It is the undefined equivalent of the empty C() list, except that the -latter is defined and means there are 0 arguments here. The CNil value returns -itself if you iterate it or try to get a positional value from it, but +There is a special CParcel value named CNil. It means there +is no value here. It is the undefined equivalent of the empty +C() list, except that the latter is defined and means there are +0 arguments here. The CNil value returns itself if you iterate +it or try to get a positional value from it via subscripting, but interpolates as a null list into flat context, and an empty CSeq -into slice context. Since method calls are performed directly on -any object, CNil.defined returns CFalse while C().defined returns CTrue. +into slice context. In either case, a warning is issued. +Since method calls are performed directly on any object, CNil +can respond to certain method calls. CNil.defined returns +CFalse (whereas C().defined returns CTrue). CNil.so also +returns CFalse. CNil.ACCEPTS is always false. CNil.perl and +CNil.Str return CNil. CNil.Stringy returns '' with a warning. +CNil.Numeric returns 0 with a warning. Any undefined method call +on CNil returns CNil, so that CNil propagates down method +call chains. + Assigning CNil to any scalar container causes the container to throw out any contents and restore itself to an uninitialized state (after which it will contain a type object
r31680 -[S32/Temporal] Added to Date: There are also Cweek, Cweek-year, Cweek-number, Cweekday-of-month, and Cday-of-year methods, which work just like their DateTime equivalents.
Author: Kodi Date: 2010-07-14 16:35:46 +0200 (Wed, 14 Jul 2010) New Revision: 31680 Modified: docs/Perl6/Spec/S32-setting-library/Temporal.pod Log: [S32/Temporal] Added to Date: There are also Cweek, Cweek-year, Cweek-number, Cweekday-of-month, and Cday-of-year methods, which work just like their DateTime equivalents. Modified: docs/Perl6/Spec/S32-setting-library/Temporal.pod === --- docs/Perl6/Spec/S32-setting-library/Temporal.pod2010-07-14 14:35:21 UTC (rev 31679) +++ docs/Perl6/Spec/S32-setting-library/Temporal.pod2010-07-14 14:35:46 UTC (rev 31680) @@ -16,7 +16,7 @@ Created: 19 Mar 2009 Last Modified: 14 Jul 2010 -Version: 11 +Version: 12 The document is a draft. @@ -244,6 +244,9 @@ $d.days-in-month# 31 $d.Str # '2010-12-24' +There are also Cweek, Cweek-year, Cweek-number, Cweekday-of-month, +and Cday-of-year methods, which work just like their DateTime equivalents. + =head2 Arithmetics $d.succ # Date.new('2010-12-25')
r31598 -[S32/Temporal] Clarified the distinction between time and now, specified what formatters and time zones should actually do, and dropped some formatting methods.
Author: Kodi Date: 2010-07-09 19:43:53 +0200 (Fri, 09 Jul 2010) New Revision: 31598 Modified: docs/Perl6/Spec/S32-setting-library/Temporal.pod Log: [S32/Temporal] Clarified the distinction between time and now, specified what formatters and time zones should actually do, and dropped some formatting methods. Modified: docs/Perl6/Spec/S32-setting-library/Temporal.pod === --- docs/Perl6/Spec/S32-setting-library/Temporal.pod2010-07-09 17:12:58 UTC (rev 31597) +++ docs/Perl6/Spec/S32-setting-library/Temporal.pod2010-07-09 17:43:53 UTC (rev 31598) @@ -48,31 +48,32 @@ are the aspects of time that are felt to be stable enough to belong in the core. +Note that in this document, the term POSIX time means the number of +seconds since midnight UTC of 1 January 1970, not counting leap seconds. +This is the same as the output of the ISO C Ctime function except that it +includes a fractional part. + =head1 Ctime -Returns an CInstant representing the current time as measured in -atomic seconds since the Unix epoch, suitable for feeding to some of the -CDateTime constructors. +Returns the current POSIX time. Use the Cnow function for an +epoch-agnostic measure of atomic seconds (i.e., an CInstant). =head1 CDateTime A CDateTime object describes the time as it would appear on someone's -calendar and someone's clock. You can create a CDateTime object from -the CInstant returned by the Ctime function: +calendar and someone's clock. You can create a CDateTime object from an +CInstant or from any object that does the CNumeric role; in the latter +case, the argument is interpreted as POSIX time. -my $now = DateTime.from-epoch(time); +my $now = DateTime.new(now); +my $now = DateTime.new(time); # same thing -This is such a common use case, that there's a CDateTime.now -constructor that does this for you: +Or you can use named arguments: -my $now = DateTime.now(); - -General dates can be specified through the Cnew constructor: - my $moonlanding = DateTime.new( :year(1969), :month(7), :day(16), :hour(20), :minute(17) ); # UTC time -The full list of named arguments is as follows: +This form allows the following arguments: :year required :month defaults to 1 range 1..12 @@ -80,25 +81,34 @@ :hour defaults to 0 range 0..23 :minute defaults to 0 range 0..59 :second defaults to 0 range 0.0..^62.0 -:timezone defaults to '+' (UTC) -:formatter defaults to an iso8601 formatter, see below -Another multi exists with CDate :date -instead of C:year, C:month and C:day (and the same defaults as listed -above). +Another multi exists with CDate :date instead of C:year, C:month and +C:day (and the same defaults as listed above). -A shorter way to send in date and time information to is providing a -single string with a full ISO8601 date and time. The example from above +All four of the aforementioned forms of Cnew accept two additional named +arguments. C:formatter is a callable object that takes a CDateTime and +returns a string. The default formatter creates an ISO 8601 timestamp (see +below). C:timezone is a callable object that takes a CDateTime and +returns a two-element list giving the difference from UTC in (possibly both +negative, but not of opposite signs) hours and minutes. Alternatively, +C:timezone can be a two-element CSeq, which is interpreted as a static +offset from UTC. The default time zone is C(0, 0) (i.e., UTC). + +A shorter way to send in date and time information is to provide a +single string with a full ISO 8601 date and time. The example from above would then be my $moonlanding = DateTime.new( '1969-07-16T20:17:00Z' ); # UTC time -The general form is C[date]T[time][offset], with [date] given -as C-MM-DD and [time] given as Chh:mm:ss. +The general form is C[date]T[time][offset], with [date] given as +C-MM-DD and [time] given as Chh:mm:ss. The final CZ is a short +form for C+, meaning UTC. (Note that while this form of Cnew +accepts all of C+, C-, and CZ, the default formatter for +CDateTime always expresses UTC as CZ.) The general notation for the C +offset is C+hhmm or C-hhmm. As before, a C:formatter argument is +permitted. The C:timezone, if not supplied, is assumed to be a static +offset equal to the offset in the given timestamp. -The final CZ is a short form for C+, meaning UTC time. The -general notation for the C offset is C+hhmm or C-hhmm. - With all the above constructors, if you attempt to pass in values that are outside of the ranges specified in the list above, you'll get an exception. An exception will also be thrown if the particular day @@ -107,12 +117,19 @@ done against leap seconds. This class also explicitly does not check against ambiguous or invalid local times caused by Daylight Saving Time. +There's one additional
Re: Aliasing methods in CPAN roles
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 :)
lvalue methods
I recently attempted to write a sample mutable role that made use of a number of lvalue methods, and I had a bear of a time getting it to work. Could we arrange for a more intuitive option to be available? For example, allow the programmer to pass a writer code block in through the rw trait, and assume that the default codeblock is a reader codeblock. Something like: method x() is rw( { $.x = $_ } ) { return $.x } The idea is that if this is being called as an rvalue, the { return .x } block would be called, but if it's being called as an lvalue, the { .x = $_ } block would be called. The above example is of course trivial. A more serious example might be one based off of a coordinate system: role point { has Num $x, Num $y; method angle() is rw( { $.x = .r * cos($_); $.y = .r * sin($_) } ) { return atn($.y/$.x) } method r() is rw( { $.x = $_ * cos(.angle); $.y = $_ * sin(.angle) } ) { return sqrt($.x * $.x + $.y * $.y ) } } This strikes me as being much more readable than the current approach of explicitly returning a proxy object. I'd even be fine if the above were treated as syntactic sugar for the creation of a proxy object - that is, have: method x() is rw( { $.x = $_ } ) { return $.x } be exactly equivalent to something like: method x($val) is rw { return new Proxy: FETCH = method { return $.x }, STORE = method { $.x = $_ } } ...but without the programmer having to worry about how to access the role's attributes from within the proxy object. -- Jonathan Dataweaver Lang
Re: lvalue methods
On 2009-Oct-20, at 8:04 am, Jon Lang wrote: The above example is of course trivial. A more serious example might be one based off of a coordinate system: role point { has Num $x, Num $y; method angle() is rw( { $.x = .r * cos($_); $.y = .r * sin($_) } ) { return atn($.y/$.x) } method r() is rw( { $.x = $_ * cos(.angle); $.y = $_ * sin(.angle) } ) { return sqrt($.x * $.x + $.y * $.y ) } } This strikes me as being much more readable than the current approach of explicitly returning a proxy object. I'd even be fine if the above were treated as syntactic sugar for the creation of a proxy object - And/or some sugar for using special STORE methods on a variable, e.g.: has $angle is set { $.x = .r * cos($_); $.y = .r * sin($_) }; (Well, in this example that makes extra storage space for the $angle attribute which we don't actually want, but there are many cases where an easy way to override STORE is really what is useful rather than an lvalue sub.) But one of the problems with lvalue subs that don't simply return a variable (or equivalently, my is set example) is that you can't say things like temp lvalue() unless temp is receiving an actual variable to work on. In the case where angle() (or $.angle) is changing $.x and $.y, should trying to temporize it do temp $.x and temp $.y as well? Should it be impossible? Can Perl tell whether it should be impossible or not? Does it need to be illegal to change other variables inside a STORE? Meanwhile, the flip side to wanting an easy way to do is set is that often when someone reaches for an lvalue sub, all he really wants is a way to pass an arg to the sub that looks like assignment. For example wanting foo($x) = $y to be a prettier way to write foo($x, $y). This could be handled by, say, having a special rvalue keyword in signatures, e.g.: sub foo($x, rvalue $y?) { ... } foo(42); # $y is undef foo(42) = 24;# $y is 24 foo(42, 24); # syntax error This has the advantage of often doing what people want, and the disadvantage of not working with temp, etc. At least Perl could know that temp isn't allowed to work with such subs, though. On the other hand, something that looks like an assignment ought to work like an assignment, including temp Especially since if you want something that looks more assignment-y than passing a regular arg, we already have a way to do that, namely, using the == syntax to feed args into a slurpy parameter. But in your angle example, we really do want an assignment because the net result is to assign stuff. Perhaps method angle is setting ($.x, $.y) ... to indicate that whatever is done to angle should really affect $x and $y, and any other attributes that aren't specified may not be used. -David
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
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
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: Aliasing methods in CPAN roles
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
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
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: Freezing role methods
Ovid wrote: At the BBC, we never encounter this because semantically different methods are renamed and semantically identical methods are refactored (aliasing and excluding being code smells). However, if roles start making their way on to the CPAN, you won't necessarily have control over the source code, forcing you to fork or simply not use the role in question. Regrettably, that defeats the purpose of roles -- namely, to facilitate code reuse. Taking this idea further. If roles make their way to CPAN, and code reuse becomes practical, aliasing and excluding are no longer code smells, but appropriate ways of filtering what is wanted from generic code.
Re: Aliasing methods in CPAN roles
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
Re: Freezing role methods
Ovid wrote: I recently was trying to research some composition issues with roles and one of the researchers directed me to this paper: http://scg.unibe.ch/archive/papers/Duca07b-FreezableTrait.pdf Basically, the problem they have is this T1 (Trait 1) and T2 each implement a public x() method and other methods in T1 and T2 rely on their respective versions of x() and trying to rely on another version breaks those methods. When class C tries to compose these roles, it has a problem. It can't exclude one x() because that breaks the role which needs the excluded x(). It can't override x() because you'll likely break both roles. You *could* (this wasn't explained in the paper) extract those methods into C::x(), check your callers and dispatch as appropriate, but that would get very problematic, particularly with roles composed of other roles. snip How would Perl 6 approach this issue? S14 states: Roles may be composed into a class at compile time, in which case you get automatic detection of conflicting methods. A role may also be mixed into a class or object at run time to produce an anonymous derived class with extra capabilities, but in this case conflicting methods are overridden by the new role silently. In either case, a class is necessary for instantiation--a role may not be directly instantiated. This indicates to me that for perl6 the conflict is detected and reported to the programmer to resolve. The compiler is not required to resolve the conflict. Later S14 has: There are several ways to solve method conflicts. The first is simply to write a class method that overrides the conflicting role methods, perhaps figuring out which role method to call. Alternately, if the role's methods are declared |multi|, they can be disambiguated based on their long name. If the roles forget to declare them as multi, you can force a multi on the roles' methods by installing a proto stub in the class being constructed: proto method shake {...} Am I wrong in thinking the spec answers the question?
Re: Freezing role methods
--- On Thu, 15/10/09, Richard Hainsworth rich...@rusrating.ru wrote: From: Richard Hainsworth rich...@rusrating.ru Basically, the problem they have is this T1 (Trait 1) and T2 each implement a public x() method and other methods in T1 and T2 rely on their respective versions of x() and trying to rely on another version breaks those methods. When class C tries to compose these roles, it has a problem. It can't exclude one x() because that breaks the role which needs the excluded x(). It can't override x() because you'll likely break both roles. You *could* (this wasn't explained in the paper) extract those methods into C::x(), check your callers and dispatch as appropriate, but that would get very problematic, particularly with roles composed of other roles. snip How would Perl 6 approach this issue? S14 states: Roles may be composed into a class at compile time, in which case you get automatic detection of conflicting methods. A role may also be mixed into a class or object at run time to produce an anonymous derived class with extra capabilities, but in this case conflicting methods are overridden by the new role silently. In either case, a class is necessary for instantiation--a role may not be directly instantiated. This indicates to me that for perl6 the conflict is detected and reported to the programmer to resolve. The compiler is not required to resolve the conflict. Later S14 has: There are several ways to solve method conflicts. The first is simply to write a class method that overrides the conflicting role methods, perhaps figuring out which role method to call. snip Am I wrong in thinking the spec answers the question? Reading the paper I linked to could help to clarify the issue. In short, there are times under my current understanding of roles where you *can't* resolve the conflicts. Two roles, each providing and dependent upon a method x(), such that if either tries to use the other's x(), the code will fail. Thus, you cannot choose one x() over the other. frozen traits suggests that the composing class determine which x() it wants and statically binding the other x() to its role, thus guaranteeing that no role can get the wrong x(), but still allowing classes full control over their composition. I need to read the other responses more closely to understand their reasoning. So far, they seem wrong to me, but that's probably because I'm not reading them closely enough. Cheers, Ovid -- Buy the book - http://www.oreilly.com/catalog/perlhks/ Tech blog- http://use.perl.org/~Ovid/journal/ Twitter - http://twitter.com/OvidPerl Official Perl 6 Wiki - http://www.perlfoundation.org/perl6
Re: Freezing role methods
On Thu, Oct 15, 2009 at 10:07 AM, Ovid publiustemp-perl6langua...@yahoo.com wrote: Reading the paper I linked to could help to clarify the issue. In short, there are times under my current understanding of roles where you *can't* resolve the conflicts. Two roles, each providing and dependent upon a method x(), such that if either tries to use the other's x(), the code will fail. Thus, you cannot choose one x() over the other. frozen traits suggests that the composing class determine which x() it wants and statically binding the other x() to its role, thus guaranteeing that no role can get the wrong x(), but still allowing classes full control over their composition. I need to read the other responses more closely to understand their reasoning. So far, they seem wrong to me, but that's probably because I'm not reading them closely enough. What if there are genuinely situations when you cannot combine two roles into the same class? Do all combinations have to be possible? As TSa said, a role depending on one of its own public methods is asking for trouble when it gets combined with something else with a conflicting method, so perhaps what we should really be thinking about is how to write well-behaved roles.
Re: Freezing role methods
Ovid wrote: --- On Thu, 15/10/09, Richard Hainsworth rich...@rusrating.ru wrote: Later S14 has: There are several ways to solve method conflicts. The first is simply to write a class method that overrides the conflicting role methods, perhaps figuring out which role method to call. snip Am I wrong in thinking the spec answers the question? Reading the paper I linked to could help to clarify the issue. In short, there are times under my current understanding of roles where you *can't* resolve the conflicts. Two roles, each providing and dependent upon a method x(), such that if either tries to use the other's x(), the code will fail. Thus, you cannot choose one x() over the other. The paper you linked to states: 2.2 Trait conflict resolution limits While trait composition lets the class composer resolve conflicts by redefining in the composer or ... The paper explains how conflicts arise and they are detected because fundamentally different methods have the same name. But the assumption in the paper is that the class composer resolves the conflict, without further programmer intervention. The perl6 spec does not require the class composer to resolve the conflict only to detect it. Given the explanation in the spec about conflict resolution, it is my understanding that it is the programmer's task to rewrite to eliminate the conflict.
Re: Freezing role methods
--- On Thu, 15/10/09, Richard Hainsworth rich...@rusrating.ru wrote: From: Richard Hainsworth rich...@rusrating.ru But the assumption in the paper is that the class composer resolves the conflict, without further programmer intervention. The perl6 spec does not require the class composer to resolve the conflict only to detect it. Given the explanation in the spec about conflict resolution, it is my understanding that it is the programmer's task to rewrite to eliminate the conflict. Ugh. That's ambiguity in the paper. Thanks for pointing that out. The specific intention is that the programmer has to specifically address this issue (in this case, by potentially freezing one or more methods). At the BBC, we never encounter this because semantically different methods are renamed and semantically identical methods are refactored (aliasing and excluding being code smells). However, if roles start making their way on to the CPAN, you won't necessarily have control over the source code, forcing you to fork or simply not use the role in question. Regrettably, that defeats the purpose of roles -- namely, to facilitate code reuse. Cheers, Ovid -- Buy the book - http://www.oreilly.com/catalog/perlhks/ Tech blog- http://use.perl.org/~Ovid/journal/ Twitter - http://twitter.com/OvidPerl Official Perl 6 Wiki - http://www.perlfoundation.org/perl6
Freezing role methods
I recently was trying to research some composition issues with roles and one of the researchers directed me to this paper: http://scg.unibe.ch/archive/papers/Duca07b-FreezableTrait.pdf Basically, the problem they have is this T1 (Trait 1) and T2 each implement a public x() method and other methods in T1 and T2 rely on their respective versions of x() and trying to rely on another version breaks those methods. When class C tries to compose these roles, it has a problem. It can't exclude one x() because that breaks the role which needs the excluded x(). It can't override x() because you'll likely break both roles. You *could* (this wasn't explained in the paper) extract those methods into C::x(), check your callers and dispatch as appropriate, but that would get very problematic, particularly with roles composed of other roles. The only way to handle this appears to be renaming one of the x() methods and trying to track down all code which relies on it and changing it. This essentially violates the problem we're trying to solve with traits, er, roles. In short, under the original traits model, you have roles you can't compose together. The paper argues that in languages which have public and private methods, that the composing class is allowed to decide which x() method it needs (if any) and that it can *freeze* the other x() method. That is to say, the x() in question would become private and statically bound to the invocants to ensure that they're always calling the correct x(). How would Perl 6 approach this issue? Cheers, Ovid -- Buy the book - http://www.oreilly.com/catalog/perlhks/ Tech blog- http://use.perl.org/~Ovid/journal/ Twitter - http://twitter.com/OvidPerl Official Perl 6 Wiki - http://www.perlfoundation.org/perl6
Re: Freezing role methods
Ovid wrote: The only way to handle this appears to be renaming one of the x() methods and trying to track down all code which relies on it and changing it. This essentially violates the problem we're trying to solve with traits, er, roles. In short, under the original traits model, you have roles you can't compose together. The paper argues that in languages which have public and private methods, that the composing class is allowed to decide which x() method it needs (if any) and that it can *freeze* the other x() method. That is to say, the x() in question would become private and statically bound to the invocants to ensure that they're always calling the correct x(). How would Perl 6 approach this issue? The fundamental problem is that there are times when you need both versions of a given method to be available, but you don't want to rename either of them. This leads to a namespace clash. The initial possibility that springs to mind would be to use longnames to disambiguate between the two options - specifically, by means of the invocant: role T1 { method foo() } role T2 { method foo() } class C does T1 does T2 { method foo(T1 $self:) { $self.T1::foo() } method foo(T2 $self:) { $self.T2::foo() } } ...or something to that effect. You'd still have a disambiguation issue, in that you'd somehow need to specify which hat an object of class C is wearing when you try to call the method. (I like this approach because it requires you to explicitly identify that the class is deferring the disambiguation, rather than having it silently occur behind the scenes.) Much of this could be handled implicitly, by means of which role was requested when the object was passed into the current block: sub bar (T1 $x) { ... } sub baz (T2 $x) { ... } my C $x; bar $x; Since bar is expecting an object that does T1, code within bar should resolve the ambiguity involving foo in favor of foo:(T1:) - that is, within the lexical scope of sub bar, $x is wearing its T1 hat. Ditto with baz and T2. In other cases, there may be no way to implicitly disambiguate. In those cases, there would need to be an explicit way to decide which hat the object is wearing. My gut instinct would be to use the same syntax as is used to coerce an object into a particular class, but with a role name instead of a class name. It differs from coercion in that it wouldn't actually change the underlying object; all it would do would be to decide which role to favor when resolving disputes of this sort. In short, resolve the dilemma by allowing the class the option of deferring the disambiguation until the method is called, and then to try to resolve it first by means of the overall context in which the call is made. This Schrodinger's method approach doesn't fix everything; but I suspect that it should usefully handle the majority of problems that arise. -- Jonathan Dataweaver Lang
Re: Freezing role methods
--- On Wed, 14/10/09, Jon Lang datawea...@gmail.com wrote: From: Jon Lang datawea...@gmail.com The initial possibility that springs to mind would be to use longnames to disambiguate between the two options - specifically, by means of the invocant: role T1 { method foo() } role T2 { method foo() } class C does T1 does T2 { method foo(T1 $self:) { $self.T1::foo() } method foo(T2 $self:) { $self.T2::foo() } } ...or something to that effect. You'd still have a disambiguation issue, in that you'd somehow need to specify which hat an object of class C is wearing when you try to call the method. Except that if a consumer of C needs foo(), they have to fully qualify the call to foo(). That violates encapsulation. Much of this could be handled implicitly, by means of which role was requested when the object was passed into the current block: sub bar (T1 $x) { ... } sub baz (T2 $x) { ... } my C $x; bar $x; Same problem as above. Works for C, but not for consumers of C which need to call foo(). In other cases, there may be no way to implicitly disambiguate. In those cases, there would need to be an explicit way to decide which hat the object is wearing. I really don't think that deferring the decision works. The freezing technique described in the paper allows the consumer, C, to statically bind the method foo() in the methods in the appropriate role which call it. Dynamic binding defers the decision which causes implementation details to leak to consumers of C. This means that if you change your roles, your consumers will potentially need to be rewritten. Cheers, Ovid -- Buy the book - http://www.oreilly.com/catalog/perlhks/ Tech blog- http://use.perl.org/~Ovid/journal/ Twitter - http://twitter.com/OvidPerl Official Perl 6 Wiki - http://www.perlfoundation.org/perl6
Re: Freezing role methods
On 2009-Oct-14, at 8:52 am, Ovid wrote: --- On Wed, 14/10/09, Jon Lang datawea...@gmail.com wrote: The initial possibility that springs to mind would be to use longnames to disambiguate between the two options - specifically, by means of the invocant: ...or something to that effect. You'd still have a disambiguation issue, in that you'd somehow need to specify which hat an object of class C is wearing when you try to call the method. Good, that's what I was looking for the last time this came up. (http://www.nntp.perl.org/group/perl.perl6.language/2009/07/msg32164.html ) Except that if a consumer of C needs foo(), they have to fully qualify the call to foo(). That violates encapsulation. I don't see that as an encapsulation problem. A leaky encapsulation means we have to know how something works, but when I have to distinguish between $dogwood.Dog::bark and $dogwood.Tree::bark, I'm distinguishing between two wholly unrelated actions (that they happen to have some of the same letters in their names is completely coincidental). So I have to know *what* a Dogwood object does; but I still don't have to know how it does it. Or to look at it the other way around: Since we refer to things by name, those names have to be unique everywhere; so let's start out with long, fully-qualified names everywhere: $dog.Dog::bark(), $tree.Tree::bark(), $i.Int::succ, etc. Now everything's fine -- except that our fingers are getting tired from all that typing. We want to use shortcuts to say things like $dog.bark, because there's only one place that $dog can legitimately find a bark() method, and that's in the Dog class, so both we and Perl can easily figure out what is meant. On the other hand, $dogwood.Dog::bark cannot be simplified by leaving out the Dog:: because then it would be ambiguous. But if we look at it as starting with full names everywhere, and seeing what we can leave out (rather that starting with short names and having to add stuff in), I think it's not surprising. In other cases, there may be no way to implicitly disambiguate. In those cases, there would need to be an explicit way to decide which hat the object is wearing. I really don't think that deferring the decision works. The freezing technique described in the paper allows the consumer, C, to statically bind the method foo() in the methods in the appropriate role which call it. The problem with freezing some methods into private ones is that those methods weren't meant to be private; if my role provides a .bark method, I need to be able to call it. Dynamic binding defers the decision which causes implementation details to leak to consumers of C. This means that if you change your roles, your consumers will potentially need to be rewritten. But if you merely change the implementation of how bark() works (either one), nothing needs to be rewritten. If you want to change from Tree::bark-ing to Dog::bark-ing, then you *should* be rewriting code, because you're completely changing what is going on, no less than if you changed from bark()ing to fetch()ing. -David
Re: Freezing role methods
HaloO, On Wednesday, 14. October 2009 12:18:30 Ovid wrote: You *could* (this wasn't explained in the paper) extract those methods into C::x(), check your callers and dispatch as appropriate, but that would get very problematic, particularly with roles composed of other roles. I consider the dependence of T1 and T2 on their respective public method implementation a design flaw of these methods. They should each have a private service routine that in turn is called by the public x method. But here is how this can be worked around in C: role T1 { method foo { self.x } method x { say T1 } } role T2 { method bar { self.x } method x { say T2 } } class C does T1 does T2 { enum Source other from_foo from_bar has Source $!source = other; method foo { self!source = from_foo; T1::foo } method bar { self!source = from_bar; T2::bar } method x { given self!source { when from_foo { T1::x; self!source = other } when from_bar { T2::x; self!source = other } default { say C } } } } I admit that this is clumsy. So we need an automatic procedure and some nice syntax. But it looks to me as code analysis of T1 and T2 is needed to generate the wrappers in C. One point I don't like in the paper is that freezing methods can be used to erase methods from a role. This is diametrically opposed to the intent of roles to make a guaranty to provide an interface. Regards TSa. -- The unavoidable price of reliability is simplicity -- C.A.R. Hoare Simplicity does not precede complexity, but follows it. -- A.J. Perlis 1 + 2 + 3 + 4 + ... = -1/12 -- Srinivasa Ramanujan
Re: Freezing role methods
David Green wrote: Or to look at it the other way around: Since we refer to things by name, those names have to be unique everywhere; so let's start out with long, fully-qualified names everywhere: $dog.Dog::bark(), $tree.Tree::bark(), $i.Int::succ, etc. Now everything's fine -- except that our fingers are getting tired from all that typing. We want to use shortcuts to say things like $dog.bark, because there's only one place that $dog can legitimately find a bark() method, and that's in the Dog class, so both we and Perl can easily figure out what is meant. On the other hand, $dogwood.Dog::bark cannot be simplified by leaving out the Dog:: because then it would be ambiguous. But if we look at it as starting with full names everywhere, and seeing what we can leave out (rather that starting with short names and having to add stuff in), I think it's not surprising. On the gripping hand, if we have a function train(Dog $d), then we can safely assume that within the lexical scope of train, $d is supposed to be treated as a Dog. So within that lexical scope, it should be safe to leave off the Dog::. If you pass $dogwood into this method, the ambiguity between Dog::bark and Tree::bark gets resolved in favor of the former; so $d.bark _still_ barks like a Dog, even though $d is actually a Dogwood. That's what I was meaning when I talked about wearing hats: while it's within the train() sub, $dogwood is wearing its Dog hat and barks like a Dog. I really don't think that deferring the decision works. The freezing technique described in the paper allows the consumer, C, to statically bind the method foo() in the methods in the appropriate role which call it. The problem with freezing some methods into private ones is that those methods weren't meant to be private; if my role provides a .bark method, I need to be able to call it. And more to the point, subs that aren't expecting a Dogwood should still be able to accept it in its role as a Dog, call .bark, and expect it to bark like a Dog. -- Jonathan Dataweaver Lang
Re: Freezing role methods
On 2009-Oct-14, at 2:00 pm, Jon Lang wrote: David Green wrote: On the other hand, $dogwood.Dog::bark cannot be simplified by leaving out the Dog:: because then it would be ambiguous. On the gripping hand, if we have a function train(Dog $d), then we can safely assume that within the lexical scope of train, $d is supposed to be treated as a Dog. So within that lexical scope, it should be safe to leave off the Dog::. Yes; and then my question from last time is whether the sig (Dog $d) soft-casts the arg such that the non-doggy bits of $d still remain, e.g. if inside train() we call a function chop(Tree $t), chop() will unambiguously see the Tree-half of the original Dogwood object. Or will it be hard-cast such that the non-doggy bits are simply lost? (And if so, does an ordinary cast Foo($d) do the same thing, or is one hard and one soft, etc.?) The soft way -- being able to cast $dogwood as a Dog and treat it unambiguously so, then to do the same thing treating it as a Tree object -- is the most flexible. Split-personality Dogs may be rare, but I can imagine wanting to call common utility roles (e.g. Logging) from any point down a calling chain. However, I expect that my Dog $d = $dogwood would strip out everything else, on the grounds that you explicitly requested a pure Dog object. Otherwise you could have said my $d = Dog($dogwood) or maybe my $dogwood.^WHAT $d = $dogwood instead. -David
Re: Freezing role methods
David Green david.gr...@telus.net writes: The soft way -- being able to cast $dogwood as a Dog and treat it unambiguously so, then to do the same thing treating it as a Tree object -- is the most flexible. Split-personality Dogs may be rare, but I can imagine wanting to call common utility roles (e.g. Logging) from any point down a calling chain. It may be the time of day, but I imagine the Tree type may have something to say about Logging. Eirik, logging off -- Ever heard of .cshrc? That's a city in Bosnia. Right? (Discussion in comp.os.linux.misc on the intuitiveness of commands.)
Re: Freezing role methods
David Green wrote: Jon Lang wrote: David Green wrote: On the other hand, $dogwood.Dog::bark cannot be simplified by leaving out the Dog:: because then it would be ambiguous. On the gripping hand, if we have a function train(Dog $d), then we can safely assume that within the lexical scope of train, $d is supposed to be treated as a Dog. So within that lexical scope, it should be safe to leave off the Dog::. Yes; and then my question from last time is whether the sig (Dog $d) soft-casts the arg such that the non-doggy bits of $d still remain, e.g. if inside train() we call a function chop(Tree $t), chop() will unambiguously see the Tree-half of the original Dogwood object. Or will it be hard-cast such that the non-doggy bits are simply lost? (And if so, does an ordinary cast Foo($d) do the same thing, or is one hard and one soft, etc.?) Here, we need a bit of a clarification: are we talking roles or classes? Real example: Numeric is a role; Num is a class. Both can be used in signatures; but only classes can be used to create objects. That is, my Num $x; works; but my Numeric $x; doesn't. As such, you cannot coerce an object to a role; you can only coerce it to a class that does that role. And when passing parameters, you don't coerce the object at all. You smart-match the prospective object against the criteria provided by the signature to determine whether or not it's acceptable. ...which is a long-winded way of saying that it would be like a soft cast: all of the object's capabilities remain intact after being passed as a parameter; the only thing that would change would be that the lexical scope inside the routine would show a preference for the Dog-like features of the object. If you asked for a Dog, it's reasonable to assume that you were given a Dog. And the way I see it working, this preference would only show up in one very specific circumstance: namely, when the object in question has multiple methods that are distinguished from each other by their invocant types. When in a lexical scope that shows a preference for $dogwood to play the role of a Dog, a call to $dogwood.bark() would result in MMD looking at bark:(Dog $dogwood:) and bark:(Tree $dogwood:) and choosing the former. When in a lexical scope where the preference is for $dogwood as a Tree, it would resolve the decision in favor of the latter. And if neither or both are preferred roles for $dogwood, it would fail on account of too much ambiguity. 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:() And because of the flattening nature of role composition, the latter doesn't work: after you have composed Dog and Tree into Dogwood, objects that are based on Dogwood no longer have access to the methods provided by Dog or Tree; they only have access to the methods that Dogwood provides. (Caveat: if Dogwood doesn't explicitly provide a method corresponding to something found in Dog or Tree, it does so implicitly.) This is perhaps the most crucial difference between role composition and class inheritance: once role composition is complete, you can ignore the implementation details of the roles that were composed; all that matters is the implementation of the role or class into which they were composed. However, I expect that my Dog $d = $dogwood would strip out everything else, on the grounds that you explicitly requested a pure Dog object. Otherwise you could have said my $d = Dog($dogwood) or maybe my $dogwood.^WHAT $d = $dogwood instead. With my Dog $d = $dogwood, $d is a Dog that was initialized using values gleaned from $dogwood. -- Jonathan Dataweaver Lang
Re: Freezing role methods
Jon Lang wrote: Here, we need a bit of a clarification: are we talking roles or classes? Real example: Numeric is a role; Num is a class. Both can be used in signatures; but only classes can be used to create objects. That is, my Num $x; works; but my Numeric $x; doesn't. As such, you cannot coerce an object to a role; you can only coerce it to a class that does that role. Bad example. Both of those would work. Otherwise one of the main reasons for roles to exist, which is to be able to declare a container $x and say that it may hold anything that does role Y, wouldn't be possible. Perhaps a better example is Num.new(...) works but Numeric.new(...) doesn't. -- Darren Duncan
Re: Freezing role methods
Darren Duncan wrote: Jon Lang wrote: Here, we need a bit of a clarification: are we talking roles or classes? Real example: Numeric is a role; Num is a class. Both can be used in signatures; but only classes can be used to create objects. That is, my Num $x; works; but my Numeric $x; doesn't. As such, you cannot coerce an object to a role; you can only coerce it to a class that does that role. Bad example. Both of those would work. Otherwise one of the main reasons for roles to exist, which is to be able to declare a container $x and say that it may hold anything that does role Y, wouldn't be possible. Perhaps a better example is Num.new(...) works but Numeric.new(...) doesn't. -- You are, of course, correct. I think that what I meant to say was my $x is Num vs. my $x is Numeric. -- Jonathan Dataweaver Lang
Re: Freezing role methods
On 10/14/09, Ovid publiustemp-perl6langua...@yahoo.com wrote: In short, under the original traits model, you have roles you can't compose together. The paper argues that in languages which have public and private methods, that the composing class is allowed to decide which x() method it needs (if any) and that it can *freeze* the other x() method. That is to say, the x() in question would become private and statically bound to the invocants to ensure that they're always calling the correct x(). How would Perl 6 approach this issue? Hrm, to clarify for myself, would this imply that roles have a specialised MRO, such that, they would resolve methods as (in order from highest preference to lowest): 1/ Implemented by the class they're composed into. 2/ The role that the called method is defined in. 3/ Any roles that the role the method is called on are composed into. This seems to be the only thing which would make sense. This would avoid unexpected action-at-a-distance, when two roles with similarly-named internal methods (whether public or private) are consumed into the same class, or to avoid roles having to know too much about other roles which aren't composed into the current role's implementations. Mark.
Should .^methods be curried with the invocant?
Consider this case: class A { method m { say 'OH HAI' } }; my $m = A.new.^methods(:local).[0]; How should I invoke $m? In current Rakudo this works: $m(A.new); # supply the invocant as first argument But shouldn't be just $m() (invocant magically curried) or may $m(A.new:) (invocant not curried, but marked with a colon)? Cheers, Moritz
Re: Should .^methods be curried with the invocant?
Em Sex, 2009-09-25 às 18:28 +0200, Moritz Lenz escreveu: class A { method m { say 'OH HAI' } }; my $m = A.new.^methods(:local).[0]; How should I invoke $m? In current Rakudo this works: $m(A.new);# supply the invocant as first argument But shouldn't be just $m() (invocant magically curried) or may $m(A.new:) (invocant not curried, but marked with a colon)? Methods are only methods when they are dispatched as methods, otherwise they are regular subs. The invocant in the capture is just the first positional argument, so $m(A.new) is what you want, although $m(A.new: ) should have the same effect. daniel
Re: RFC: overriding methods declared by roles (Was: Re: Reusing code: Everything but the kitchen sink)
- Original Message From: Jon Lang datawea...@gmail.com Right. But as they were originally conceived, they were interfaces that could also handle code reuse, rather than units of code reuse that could also be used as interfaces. From this perspective, it makes perfect sense that a role's methods can be overridden as easily as they are. As originally conceived in Perl 6 or in the original traits papers? In the original research, the purpose of roles was to allow the decoupling of responsibility and behavior (code reuse) found in inheritance-based OO systems. Traits (roles) took over code reuse. But you make a good point: there are some (a few? most?) programmers who are going to want to use roles primarily for code reuse, and who will want it to be a little more difficult to override the code provided by a role (e.g., requiring the use of supersede and perhaps augment in order to replace the definition with a new one). Just to give people some real data to play with (our system may not be representative), here's some sample source code and some imformation about our use of roles in the BBC. package PIPs::ResultSource::Series; use Moose; extends 'PIPs::ResultSourceBase::BrandSeries'; with qw( PIPs::ResultSource::Role::DoesParentChildRelationships PIPs::ResultSource::Role::DoesTags PIPs::ResultSource::Role::DoesContentObject PIPs::ResultSource::Role::DoesInspector PIPs::ResultSource::Role::DoesRelatedLinks PIPs::ResultSource::Role::DoesIdentifiers PIPs::ResultSource::Role::DoesChangeEvents ); (The astute reader will not that the base class is awful, but it's been a long, hard slog to get this far). Most of our classes which implement roles have similar preambles, but with different behaviors listed. Other points of interest. Only 11 of 114 classes which implement roles exclude any methods (none use method aliasing) and we currently have 40 roles implemented. Only three classes provide methods which override role's methods, but in the few cases they do, we explicitly exclude the methods from the role to make it clear that we need to do this. We had more overriding of role's methods, but continual refactoring has pushed those into roles. So we're very, very heavily on the use roles for shared behavior side. The relative paucity of overridden role methods suggests to me that (for our code), the annoyance of having to be explicit for overridding a role's methods easily offset by how hard it's been to debug this issue. That being said, the pain in debugging might have been a side effect of the fast transformation from a complex inheritance hierarchy to a roles-based system. Cheers, Ovid -- Buy the book - http://www.oreilly.com/catalog/perlhks/ Tech blog- http://use.perl.org/~Ovid/journal/ Twitter - http://twitter.com/OvidPerl Official Perl 6 Wiki - http://www.perlfoundation.org/perl6
RFC: overriding methods declared by roles (Was: Re: Reusing code: Everything but the kitchen sink)
Em Sex, 2009-07-10 às 15:39 -0700, Jon Lang escreveu: The key to understanding roles is to note that roles don't implement methods; classes implement methods. Er, while I see your point, Roles are not just interfaces... they are OO components that can be plugged into other classes. They often are used for type identity exactly because of that attribute, since you won't be enforcing any hierarchy. Roles define which methods must be implemented, and suggest ways that they might be implemented; classes decide which implementation to use. Anything that breaks this paradigm is a Bad Thing. That's not the common conception in Roles usage, specially in Moose. As I said, Roles are not just interfaces, they are OO reuseable components. The spec itself says: Classes are primarily for instance management, not code reuse. Consider using Croles when you simply want to factor out common code. The key issue here is Perl 6 wasn't yet used to the extent that Moose::Roles are, and Moose people have identified that the use of Roles as reusable components raised the issue when the class inadvertedly overrides one of the methods that are implemented by one of the composed roles. I did think that this should be the expected behavior, but when the people that is heavily using it says it took me a lot of time to debug, it indicates that there's something wrong with the behavior. So now I changed my mind, inheritance is about overriding behavior, so when you implement a method in the subclass it is a natural thinking that this should override the superclass, but when you think about it really carefully this logic doesn't really map well to Roles (considering roles as OO reuseable components). That being said, I'd think the following as an interesting solution: role R1 { method foo() {...} # degenerates to interface } role R2 does R1 { method bar() { # some implementation } method baz() { # some implementation } } class Bla does R2 { method foo { # implementing here is natural, since the role only # declared a stub, it's even a warning not to implement it } supersede method bar { # explicitly tells that I want to ignore the implementation # in the role. nextsame wouldn't find the role implementation. } augment method baz { # explicitly tells that I want to provide an additional # implementation besides the one in the role. nextsame would find # the role implementation. } } In the above example, declaring a method without either supersede or augment would result in a compile-time warning, while using augment semantics by default. dainel
Re: RFC: overriding methods declared by roles (Was: Re: Reusing code: Everything but the kitchen sink)
On 2009-Jul-12, at 12:43 pm, Daniel Ruoso wrote: role R1 { method foo() {...} # degenerates to interface } Just wondering: since merely declaring an interface will be common enough, should we be able to say simply method foo; inside a role, and drop the {...}? class Bla does R2 { method foo { # implementing here is natural, since the role only # declared a stub, it's even a warning not to implement it } supersede method bar { # explicitly tells that I want to ignore the implementation # in the role. nextsame wouldn't find the role implementation. } augment method baz { # explicitly tells that I want to provide an additional # implementation besides the one in the role. nextsame would find # the role implementation. } } Works for me. I thought having suggest to make it work the other way around sounded useful too, but perhaps you think in practice it wouldn't be worth it? -David
Re: RFC: overriding methods declared by roles (Was: Re: Reusing code: Everything but the kitchen sink)
Daniel Ruoso wrote: Jon Lang wrote: The key to understanding roles is to note that roles don't implement methods; classes implement methods. Er, while I see your point, Roles are not just interfaces... they are OO components that can be plugged into other classes. They often are used for type identity exactly because of that attribute, since you won't be enforcing any hierarchy. Right. But as they were originally conceived, they were interfaces that could also handle code reuse, rather than units of code reuse that could also be used as interfaces. From this perspective, it makes perfect sense that a role's methods can be overridden as easily as they are. But you make a good point: there are some (a few? most?) programmers who are going to want to use roles primarily for code reuse, and who will want it to be a little more difficult to override the code provided by a role (e.g., requiring the use of supersede and perhaps augment in order to replace the definition with a new one). First and foremost, this distinction between suggested ans mandatory implementation is what I was trying to make a little more explicit in my proposal: a suggested method can be overridden by the class with no extra effort; a mandatory method requires that the class be explicit about the override. The next question is which of these approaches Perl 6 should use with roles. Currently, it's using suggested implementations; what I'm hearing you say is that you'd rather have mandatory implementations. IMHO, there's a time ans place for both; so I was trying to come up with a compromise of sorts: a way of letting the programmer select the approach that most suits his needs. Roles define which methods must be implemented, and suggest ways that they might be implemented; classes decide which implementation to use. Anything that breaks this paradigm is a Bad Thing. That's not the common conception in Roles usage, specially in Moose. As I said, Roles are not just interfaces, they are OO reuseable components. FWIW, I never said that they're just interfaces. Also, I question whether that is or is not the common conception of role usage. I readily admit that it isn't so in the programming circles that you travel in; but are you typical of the perl community in this regard? This is not a rhetorical question; the way that we end up addressing this issue hinges on this question: should roles provide suggested implementations by default, or should they provide mandatory implementations by default? Even if Perl is rich enough to provide for both, the decision of which way to go when no explicit decision has been made is an important one. The spec itself says: Classes are primarily for instance management, not code reuse. Consider using Croles when you simply want to factor out common code. Right: roles are preferable to classes when it comes to code reuse. That doesn't necessarily mean that roles are _primarily_ intended for code reuse. They _might_ be; but if so, it's because they've grown beyond their original concept. The key issue here is Perl 6 wasn't yet used to the extent that Moose::Roles are, and Moose people have identified that the use of Roles as reusable components raised the issue when the class inadvertedly overrides one of the methods that are implemented by one of the composed roles. You know what? Until Moose was mentioned in this conversation, I had never heard of it. I did think that this should be the expected behavior, but when the people that is heavily using it says it took me a lot of time to debug, it indicates that there's something wrong with the behavior. So now I changed my mind, inheritance is about overriding behavior, so when you implement a method in the subclass it is a natural thinking that this should override the superclass, but when you think about it really carefully this logic doesn't really map well to Roles (considering roles as OO reuseable components). That may indeed be the case. It's entirely possible that we may want to change things so that roles define mandated methods, and possibly introduce interfaces as a variation of roles that define suggested methods. But we may instead want to keep roles as they are, and define some other variation that works just like a role except that it mandates its methods. And its also possible that I'm fundamentally wrong about this, and that we _don't_ need both approaches available for roles. That being said, I'd think the following as an interesting solution: role R1 { method foo() {...} # degenerates to interface } role R2 does R1 { method bar() { # some implementation } method baz() { # some implementation } } class Bla does R2 { method foo { # implementing here is natural, since the role only # declared a stub, it's even a warning not to implement it } supersede method bar { # explicitly tells that I want to ignore
Private methods in Roles (Was: Re: YAPC::EU and Perl 6 Roles)
Em Qua, 2009-07-08 às 12:49 -0700, Ovid escreveu: Behavioral: if you are primarily relying on roles to provide behavior (as we do at the BBC), then silently discarding the role's behavior by providing a method of the same name in your class can lead to very confusing bugs. I've lost a lot of time debugging this behavior. That's actually a tipping point, and I'm thinking we never conceptually extrapolated the use of Roles to a point that competing Roles in a composition are bringing methods to the class that are actually relevant to that roles, but doesn't mix well with the semantics of the composed class. Maybe what we need is a way to define methods that are not composed to the class at all, but are there just for implementation sake. That could probably mean that methods declared as privates in the role should not be composed in the class, and the lookup of private methods should honor the original place of declaration... daniel
r25809 - docs/Perl6/Spec src/perl6 t/perl5 t/spec/S02-literals t/spec/S12-methods
Author: lwall Date: 2009-03-13 00:15:48 +0100 (Fri, 13 Mar 2009) New Revision: 25809 Modified: docs/Perl6/Spec/S02-bits.pod docs/Perl6/Spec/S03-operators.pod docs/Perl6/Spec/S04-control.pod docs/Perl6/Spec/S12-objects.pod src/perl6/STD.pm t/perl5/roundtrip.t t/spec/S02-literals/pairs.t t/spec/S02-literals/sub-calls.t t/spec/S12-methods/instance.t t/spec/S12-methods/syntax.t Log: [STD] special named forms foo() .foo() and $.foo() no longer support the dereferencing .() postfix syntax, since they don't actually do any dereferencing! You may still insert space using unspace however. This decrease in consistency on the syntactic level is offset by an increase in consistency on the semantic level, as suggested by rouso++. (We'd already gotten rid of the dot forms of adverbs some time ago, for similar reasons. We just didn't quite carry the idea through.) Modified: docs/Perl6/Spec/S02-bits.pod === --- docs/Perl6/Spec/S02-bits.pod2009-03-12 22:34:06 UTC (rev 25808) +++ docs/Perl6/Spec/S02-bits.pod2009-03-12 23:15:48 UTC (rev 25809) @@ -1597,7 +1597,7 @@ Unlike in Perl 5, the notation Cfoo merely stands for the Cfoo function as a Code object without calling it. You may call any Code -object with parens after it (which may, of course, contain arguments): +object by dereferencing it with parens (which may, of course, contain arguments): foo($arg1, $arg2); @@ -1613,6 +1613,29 @@ embedded comment ].($arg1, $arg2); +Note however that the parentheses around arguments in the normal +named forms of function and method calls are not postfix operators, so do +not allow the C.() form, because the dot is indicative of an actual +dereferencing operation, which the named forms aren't doing. You +may, however, use unspace to install extra space before the parens +in the forms: + +foo() # okay +foo\ () # okay +foo.() # means foo().() + +.foo() # okay +.foo\ ()# okay +.foo.() # means .foo().() + +$.foo() # okay +$.foo\ () # okay +$.foo.()# means $.foo().() + +If you Ido use the dotty form on these special forms, it will +assume you wanted to call the named form without arguments, and +then dereference the result of that. + =item * With multiple dispatch, Cfoo may actually be the name of a set Modified: docs/Perl6/Spec/S03-operators.pod === --- docs/Perl6/Spec/S03-operators.pod 2009-03-12 22:34:06 UTC (rev 25808) +++ docs/Perl6/Spec/S03-operators.pod 2009-03-12 23:15:48 UTC (rev 25809) @@ -2576,12 +2576,13 @@ (except for postfix adverbs, which may follow the parentheses provided they would not attach to some other operator by the rules of precedence). -Other than various forms of parentheses, all other postfixes are +Other than parentheses, all other postfixes are disallowed immediately after a list operator, even if there are no arguments. To add a postfix to an argumentless list operator you must write it as a function call with empty parentheses: foo.[] # ILLEGAL +foo.() # ILLEGAL foo++ # ILLEGAL foo().[]# legal foo()++ # legal (if foo() is rw) @@ -2613,7 +2614,7 @@ say foo++; ILLEGAL, need parens say foo($bar+1),$bazsay(foo($bar+1), $baz); -say foo.($bar+1),$baz say(foo($bar+1), $baz); +say foo.($bar+1),$baz ILLEGAL, need space or parens say foo ($bar+1),$baz say(foo($bar+1, $baz)); say foo .($bar+1),$baz say(foo($_.($bar+1), $baz)); Modified: docs/Perl6/Spec/S04-control.pod === --- docs/Perl6/Spec/S04-control.pod 2009-03-12 22:34:06 UTC (rev 25808) +++ docs/Perl6/Spec/S04-control.pod 2009-03-12 23:15:48 UTC (rev 25809) @@ -1193,8 +1193,8 @@ $scalar = ($x); # grouping parens because term expected if $term($x)# function call because operator expected if $term ($x) # syntax error (two terms in a row) -if $term.($x) # valid function call with dot -if $term\ .($x) # valid function call with unspace +if $term.($x) # valid function call with explicit dot deref +if $term\ .($x) # valid function call with unspace and dot Outside of any kind of expression brackets, a final closing curly on a line (not counting whitespace or comments) always reverts Modified: docs/Perl6/Spec/S12-objects.pod === --- docs/Perl6/Spec/S12-objects.pod 2009-03-12 22:34:06 UTC (rev 25808) +++ docs/Perl6/Spec/S12-objects.pod 2009-03-12 23:15:48 UTC (rev 25809) @@ -12,9 +12,9 @@ Maintainer: Larry Wall la...@wall.org Date: 27 Oct 2004 - Last Modified: 9 Mar 2009
Re: File test ops as string methods
I've been thinking about that. One interesting ramification of the current matching rule is that you could say either of: foo.io ~~ :r :x or foo ~~ :io(:r :x) where .io is whatever your casting method of choice is for turning a string into an object with the correct methods. Somehow I think .filename is a bit too long, huffmanwise. If io is casting method, which statement below is correct: say ok if 1234.io 1000; or say ok if 1234.int 1000;
Re: .perl and other methods on Junctions?
On Wed, Nov 05, 2008 at 11:28:00AM -0800, Larry Wall wrote: But it seems to me that if stringification of a junction returns a correct .perlish syntax, it's probably better to just let that happen lazily, on the assumption someone might want .perl to autothread for some reason, perhaps because .perl performs some kind of useful canonicalization prior to comparison. So I think the actual choice is driven by the fact that Str(Junction) is defined to work like you'd expect .perl to do if .perl did it, which it doesn't... This all works for me, thanks for the clarification! Pm
File test ops as string methods
I'm sure this has been hashed out somewhere I wasn't looking, but i would really prefer for pathname ops not to be mixed in to the Str class. Maybe they could be put in a Pathname subclass of Str, with a simple literal syntax or short unary operator to build such a thing from a string? -- Sent from Gmail for mobile | mobile.google.com Mark J. Reed [EMAIL PROTECTED]
Re: File test ops as string methods
On 2008 Nov 7, at 17:49, Mark J. Reed wrote: I'm sure this has been hashed out somewhere I wasn't looking, but i would really prefer for pathname ops not to be mixed in to the Str class. Maybe they could be put in a Pathname subclass of Str, with a simple literal syntax or short unary operator to build such a thing from a string? I'm inclined to agree that Str is the wrong place for them. I could see Str being autoconverted to some kind of File class which had them, though. -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [EMAIL PROTECTED] system administrator [openafs,heimdal,too many hats] [EMAIL PROTECTED] electrical and computer engineering, carnegie mellon universityKF8NH
Re: File test ops as string methods
On Fri, Nov 07, 2008 at 05:49:54PM -0500, Mark J. Reed wrote: : I'm sure this has been hashed out somewhere I wasn't looking, but i : would really prefer for pathname ops not to be mixed in to the Str : class. Maybe they could be put in a Pathname subclass of Str, with a : simple literal syntax or short unary operator to build such a thing : from a string? I've been thinking about that. One interesting ramification of the current matching rule is that you could say either of: foo.io ~~ :r :x or foo ~~ :io(:r :x) where .io is whatever your casting method of choice is for turning a string into an object with the correct methods. Somehow I think .filename is a bit too long, huffmanwise. Larry
Re: .perl and other methods on Junctions?
On Tue, Nov 04, 2008 at 01:33:09PM -0600, Patrick R. Michaud wrote: : Consider the code: : : my $x = 3 | 'foo'; : my $y = $x.perl; : : : Does $y end up as a junction of strings or as a single string? I think it may not actually matter much, if subsequent stringification of the junction produces a result with correct Perl syntax. : Asking more directly, does .perl autothread over a Junction? : If .perl does not autothread, then is there some way of knowing : which methods autothread and which do not? I think it would depend entirely on whether the Junction class defined method .perl, or relied on the authothreading implementation triggered by Object recognizing that it was handed a Junction. But it seems to me that if stringification of a junction returns a correct .perlish syntax, it's probably better to just let that happen lazily, on the assumption someone might want .perl to autothread for some reason, perhaps because .perl performs some kind of useful canonicalization prior to comparison. So I think the actual choice is driven by the fact that Str(Junction) is defined to work like you'd expect .perl to do if .perl did it, which it doesn't... : (The question of method autothreading over junctions came up at : the OSCON 2008 hackathon, but I don't know that it was ever : resolved. If it was and I've just forgotten or overlooked the : resolution, I'll be happy to have it pointed out to me.) Well, at the time we thought there might need to be some kind of VAR-like JUNCTION macro to give access to the Junction object, but if the decision is just based on whether Junction defines the method or not, that's not really necessary. And with this semantics, it's also no problem going the other way. If method .junk is defined in Junction, you can still force it to autothread by saying $junction.Object::junk(). Larry
Re: fallback semantics of list methods
HaloO, On Saturday, 14. June 2008 18:43:05 Daniel Ruoso wrote: Moritz convinced me that there's actually no real reason to support $nonlist.listmethod I wouldn´t do that either. But I come to that conclusion from the line of thought that it is generally a bad idea to block an Any slot in a multi for a mere casting operation. The whole point of type based dispatch is to name the intended type in the first place. That is, a programmer choosing the item sigil $ in combination with a list operation should be punished with a dispatch error if he doesn´t know for sure that everything he sticks in the variable is a list anyway. Note that the other way around is bloody easy in Perl 6. A @ variable can handle items just fine! I´m aware that this makes me opt for solution three, the dropping of fallback from method to sub dispatch. But I consider that a good thing. They are nicely distinct syntactically, so why mix them semantically? And if we stop, and think for more two seconds, we realise that supporting that could end up having a lot of non-interesting side effects, because an exported sub with the signature :(Any, Str) is most likely to have a lot of false hits. Technically there are no false hits on an Any slot ;) In the case at hand it listifies the item and re-dispatches. IOW, the false hits will be surprises for unaware programmers who get unexpected dispatches silently. BTW, there´s the same problem with stringification of the separator. Combining that with the listification would end up blocking *join:(Any,Any) globally. Regards, TSa. -- The unavoidable price of reliability is simplicity -- C.A.R. Hoare Simplicity does not precede complexity, but follows it. -- A.J. Perlis 1 + 2 + 3 + 4 + ... = -1/12 -- Srinivasa Ramanujan
fallback semantics of list methods
In the test suite and on IRC there was quite some confusion about how list builtins are specced, and how they should behave in corner cases. One is join(): our Str multi method join ( @values: Str $separator = ' ' ) our Str multi join ( Str $separator = ' ', [EMAIL PROTECTED] ) It is quite clear that the perl 5-style join 'sep', $value, $value2; invocation remains valid, and @list.join($sep) is the new method form. The confusion arises what to do with 'str'.join('other_str') should be. Fallback semantics in S12 suggest that since no matching multi method is found, subs are tried - that is, the expression is interpreted as join('str', 'other_str') yielding 'other_str'. t/spec/S29-list/join.t disagrees, and wants the result to be 'str'. Daniel Ruoso argued in favour of the tested behaviour, suggesting that perhaps the specs should be updated accordingly, mostly because ('str').join('other_str') would be confusing otherwise. Patrick Michaud argued in favour of the specced behaviour, and I agree. Mostly because nobody sane will write things like 'str'.join('other_str') with a literal string as the invocant in first place. And if it's not a literal, and you want it to behave as list, the invocant is either something that returns a list, or a variable with the '@' sigil. We just need to be careful that everything that should return really does that, even if it contains a single list. Currently both pugs and rakudo make a b return a list (pugs actually an array, but that's a different problem), but a is a Str. If we'd just be more consistent and always return a list, I don't see a problem with the spec. If not, it would be rather weird to have a b.join('c') return 'abc', but a.join('c') return 'c'. Consider my $x = A.new(); $x.y = a; say $x.y.join('b') The output is different for the two possible declarations of class A: class A { has $y is rw } # - b class A { has @y is rw } # - a not pretty IMHO. So I see the following options: 1) be more consistent with what returns a list 2) Add a method with invocant Any for each list builtin 3) drop method fallback, thus disallowing Str.join(Str) outright 4) be lisp, make everything a list *g* (not serious) I haven't thought a lot about the third option, and what it would mean to the language as a whole, so I have no idea if it's a viable alternative. Any thoughts on the topic are welcome. I hope I didn't confuse too much here ;-) Cheers, Moritz -- Moritz Lenz http://moritz.faui2k3.org/ | http://perl-6.de/
Re: fallback semantics of list methods
On Sat, Jun 14, 2008 at 01:46:10PM +0200, Moritz Lenz wrote: : In the test suite and on IRC there was quite some confusion about how : list builtins are specced, and how they should behave in corner cases. : : One is join(): : our Str multi method join ( @values: Str $separator = ' ' ) : our Str multi join ( Str $separator = ' ', [EMAIL PROTECTED] ) : : It is quite clear that the perl 5-style :join 'sep', $value, $value2; : invocation remains valid, and : @list.join($sep) : is the new method form. : : The confusion arises what to do with :'str'.join('other_str') : should be. : : Fallback semantics in S12 suggest that since no matching multi method is : found, subs are tried - that is, the expression is interpreted as :join('str', 'other_str') : yielding 'other_str'. t/spec/S29-list/join.t disagrees, and wants the : result to be 'str'. I want the result to be 'str'. : Daniel Ruoso argued in favour of the tested behaviour, suggesting that : perhaps the specs should be updated accordingly, mostly because :('str').join('other_str') : would be confusing otherwise. More to the point, $unknown.join('other_str') needs to work well, I think. And that means even if $unknown doesn't know whether it's singular or plural. : Patrick Michaud argued in favour of the specced behaviour, and I agree. : Mostly because nobody sane will write things like : 'str'.join('other_str') with a literal string as the invocant in first : place. And if it's not a literal, and you want it to behave as list, the : invocant is either something that returns a list, or a variable with the : '@' sigil. We just need to be careful that everything that should return : really does that, even if it contains a single list. Patrick and I discussed it on the phone the other day and came to an understanding, I think. : Currently both pugs and rakudo make a b return a list (pugs actually : an array, but that's a different problem), but a is a Str. : If we'd just be more consistent and always return a list, I don't see a : problem with the spec. If not, it would be rather weird to have a : b.join('c') return 'abc', but a.join('c') return 'c'. a.join('c') should return 'a'. : Consider : my $x = A.new(); : $x.y = a; : say $x.y.join('b') : The output is different for the two possible declarations of class A: : class A { has $y is rw } # - b : class A { has @y is rw } # - a : not pretty IMHO. Indeed. : So I see the following options: : 1) be more consistent with what returns a list : 2) Add a method with invocant Any for each list builtin : 3) drop method fallback, thus disallowing Str.join(Str) outright : 4) be lisp, make everything a list *g* (not serious) : : I haven't thought a lot about the third option, and what it would mean : to the language as a whole, so I have no idea if it's a viable alternative. I have been advocating for 2, and am considering doing 3 as well. There's more than one way to do 2--we could, for instance, have some magical syntax for saying that a class's invocant may be converted from Any. But what Patrick and I decided on Wednesday was that, for now, we'd go with the simplest approach, which is not to invent any new syntax or semantics, but simply have the Prelude install Any methods as defaults for universal methods such as .join that want to convert the invocant to a particular type across the language as a whole. No fallback is then necessary, and the fact that the Prelude is defining language-wide default semantics is not a problem at all, because that's precisely what the Prelude is for. And I don't see any problem with the Any class claiming to own .join since subclasses can still override if the like. Larry
Re: fallback semantics of list methods
Sáb, 2008-06-14 às 09:20 -0700, Larry Wall escreveu: On Sat, Jun 14, 2008 at 01:46:10PM +0200, Moritz Lenz wrote: : Fallback semantics in S12 suggest that since no matching multi method is : found, subs are tried - that is, the expression is interpreted as :join('str', 'other_str') : yielding 'other_str'. t/spec/S29-list/join.t disagrees, and wants the : result to be 'str'. I want the result to be 'str'. Just a sanity check here... Are we really going to change the order of the parameters of 'join' from p5? Are we aware that this is going to be a PITA for most p5 developers? Do we realise that this is only necessary to support $nonlist.join($separator) Which, as moritz pointed out on IRC is a very specific corner case, which only makes sense on something like: my $a = $cond ?? ( 1 ) !! ( 2, 3, 4 ); $a.join(','); Which would have the desired effect if used with the proper sigil: my @a = $cond ?? 1 !! (2,3,4); @a.join(','); If we choose to avoid supporting $nonlist.listmethod (which sounds lame anyway), we can keep the order of parameters in join join $separator, @list; join ', ', 1, 2, 3, 4; Which is considerably saner than: join 1, 2, 3, 4, ', '; Moritz convinced me that there's actually no real reason to support $nonlist.listmethod And if we stop, and think for more two seconds, we realise that supporting that could end up having a lot of non-interesting side effects, because an exported sub with the signature :(Any, Str) is most likely to have a lot of false hits. daniel
Private methods in classes and roles
S12 says (in the context of classes): my method think (Brain $self: $thought) (Such methods are completely invisible to ordinary method calls, and are in fact called with a different syntax that uses ! in place of the . character. See below.) And later on, in the context of roles: my method !foo ... my method foo ... # same, but foo is aliased to !foo Am I right in assuming that the second example is valid only for roles? I find this different syntax for classes and roles quite confusing. Is it intended that way? I'd welcome a uniform syntax. Cheers, Moritz -- Moritz Lenz http://moritz.faui2k3.org/ | http://perl-6.de/
Re: Private methods in classes and roles
and a few more thoughts: I wrote: S12 says (in the context of classes): my method think (Brain $self: $thought) (Such methods are completely invisible to ordinary method calls, and are in fact called with a different syntax that uses ! in place of the . character. See below.) for private subs S12 also says Generally you'd just use a lexically scoped sub, though. my sub foo ... [Conjectural: To put a private sub into the class, say our sub !foo ... ] Which lead me to the thought that 'my method foo' is a bad idea because the lexical scoping of the 'my' is orthogonal to the scope of the class. class A { my method foo { } } class A is also { method bar { # no way to access self!foo here } } So is our method !foo {} allowed in classes? and is it the recommended way to declare private methods? -- Moritz Lenz http://moritz.faui2k3.org/ | http://perl-6.de/
Re: Private methods in classes and roles
Moritz Lenz moritz-at-casella.verplant.org |Perl 6| wrote: S12 says (in the context of classes): my method think (Brain $self: $thought) (Such methods are completely invisible to ordinary method calls, and are in fact called with a different syntax that uses ! in place of the . character. See below.) And later on, in the context of roles: my method !foo ... my method foo ... # same, but foo is aliased to !foo Am I right in assuming that the second example is valid only for roles? I find this different syntax for classes and roles quite confusing. Is it intended that way? I'd welcome a uniform syntax. Cheers, Moritz I've asked about my method foo too, but had no response. I would not think anything is unique to roles, rather, stuff defined in a role is remembered partly-digested and spilled into a class later. You might want to look at what I've got thus far in my specdoc at http://www.dlugosz.com/Perl6/. I plan on updating that section soon, but you get the idea of the formalism I'm bringing to it. --John
Re: default parameters in methods
Larry Wall larry-at-wall.org |Perl 6| wrote: All default expressions to any parameter are defined to run in the context that assumes any parameters to their left are already bound, so you may safely depend on self already being set. OK, so there is no technical reason why it can't work that way. But, self the keyword is not $self the parameter (it only works in methods), and there are issues of trust. So I need to describe it properly. --John
default parameters in methods
It is not specified in the Synopses as I recall, but I believe that this is useful enough that it must be made to work: method bytes (Encoding :$encoding = .encoding) returns Int or even method bytes (Encoding :$encoding = self!encoding) returns Int That is, a named-only parameter, which may be used as an optional adverb or extra parameter to affect details of the function, should default to a pre-set value inside the instance. If this is not allowed, the beginning of the method would always have to check for defaults. That should be automatic. And it documents the situation nicely in the signature, without further explanation that if the parameter is not supplied... This means that the default arguments run inside the context of the method call, and can do anything that you would expect from their lexical position. --John
Re: default parameters in methods
On Fri, Apr 11, 2008 at 03:35:37AM -, John M. Dlugosz wrote: : It is not specified in the Synopses as I recall, but I believe that this is useful enough that it must be made to work: : :method bytes (Encoding :$encoding = .encoding) :returns Int : : or even : :method bytes (Encoding :$encoding = self!encoding) :returns Int : : That is, a named-only parameter, which may be used as an optional adverb or extra parameter to affect details of the function, should default to a pre-set value inside the instance. : : If this is not allowed, the beginning of the method would always have to check for defaults. That should be automatic. And it documents the situation nicely in the signature, without further explanation that if the parameter is not supplied... : : This means that the default arguments run inside the context of the method call, and can do anything that you would expect from their lexical position. All default expressions to any parameter are defined to run in the context that assumes any parameters to their left are already bound, so you may safely depend on self already being set. Larry
S12v58 edits on Methods
If you declare an explicit invocant for an Array type using an array variable... Suggest: The invocant may be given a sigil other than the C$ item sigil using the same rules as binding variables to class types as described in S02 under Names and Variables. For example, if the class does the CPositional role, it may be declared with the C@ array sigil. Naturally, declaring an explicit invocant for an Array type lets you use it in the usual way, such as using it in list context to produce its elements. The word self is described as a keyword and as a function. Be stronger about defining it. I suggest, Within the lexical scope of any method, the Cself keyword behaves as a function that returns the invocant in item context. It is improper to use this pseudo-function in any manner other than to call it directly. In particular, an implementation is not required to support taking a Capture to the function. Note, however, that you may Icall it from a closure. Also note that, as is usual with Perl, the existance of keywords do not preclude the use of identifiers with the same name. Although this is usually considerd bad form to make a variable named C$if, defining your invocant to be C$self is not deemed to be in bad taste. However, defining C@self (or other sigil forms other than item) could indeed confuse someone reading the code, and is discouraged. Per conversation with Audry, I suggest adding the following before Private methods are Methods, like any other kind of Csub, behave as if defined with Cour by default, if no scope modifier is used. This is described in S06 under Named subroutines. However, it may be desirable to use the Cour keyword explicitly, as it offers the ability to put the return type before the method name, in the C style.
Re: our methods?
John M. Dlugosz 提到: In S29, there are definitions like our Capture method shape (@array: ) is export But in S12 there is no mention as to what an our method is. It states that my is used to make private methods, and ^ to make class methods. I think this is a doc relic and should be fixed globally in that file. S02/Return types: If a subroutine is not explicitly scoped, it belongs to the current namespace (module, class, grammar, or package), as if it's scoped with the Cour scope modifier. Any return type must go after the name: So this line: our Capture method shape (@array: ) is export is really the same as: method shape (@array: ) of Capture is export The prefixing of our is there to make the return (of) type stand out. Cheers, Audrey
Re: our methods?
I understand. Thank you. This ought to be mentioned in S12. Perhaps after the treatment on my, explain that our is the default, but saying it explicitly allows the return type to be first. --John Audrey Tang audreyt-at-audreyt.org |Perl 6| wrote: John M. Dlugosz 提到: In S29, there are definitions like our Capture method shape (@array: ) is export But in S12 there is no mention as to what an our method is. It states that my is used to make private methods, and ^ to make class methods. I think this is a doc relic and should be fixed globally in that file. S02/Return types: If a subroutine is not explicitly scoped, it belongs to the current namespace (module, class, grammar, or package), as if it's scoped with the Cour scope modifier. Any return type must go after the name: So this line: our Capture method shape (@array: ) is export is really the same as: method shape (@array: ) of Capture is export The prefixing of our is there to make the return (of) type stand out. Cheers, Audrey
our methods?
In S29, there are definitions like our Capture method shape (@array: ) is export But in S12 there is no mention as to what an our method is. It states that my is used to make private methods, and ^ to make class methods. I think this is a doc relic and should be fixed globally in that file.
Re: when calling sets of methods, what happens to the return values?
Mark Stosberg wrote: S12 describes a feature to call sets of methods at the same time: http://feather.perl6.nl/syn/S12.html#Calling_sets_of_methods I would like the spec to clarify what happens to the return values of all these methods. I'm fine with a simple answer, such as that they are not available, or only the first or last set of return values is returned. As a use case, we may use of basically this feature in CGI::Application in Perl5, as part the plugin system. Each plugin location is like a method name, and as we get to each point in the code, we look up through the inheritance tree, executing methods at each location. So, Audrey implemented the beginning of this functionality: $obj.*$meth, for single inheritance. As part that she implemented return values. Her design was to compose the final return value as an unconcatenated list of each method's return value. Example: If C.foo returns (1,2,3) and D.foo returns(4,5,6) you get $obj.*$meth.[0][0] == 1 $obj.*$meth.[1][0] == 4 That works OK for me. If there's a downside, if there is a downside, it's that it could be hard to track down where a mysterious return value came from, since the return value object doesn't tell you exactly which methods were called, and in which order. Mark
when calling sets of methods, what happens to the return values?
S12 describes a feature to call sets of methods at the same time: http://feather.perl6.nl/syn/S12.html#Calling_sets_of_methods I would like the spec to clarify what happens to the return values of all these methods. I'm fine with a simple answer, such as that they are not available, or only the first or last set of return values is returned. As a use case, we may use of basically this feature in CGI::Application in Perl5, as part the plugin system. Each plugin location is like a method name, and as we get to each point in the code, we look up through the inheritance tree, executing methods at each location. In this case, I think we ignore the return values. Mark
Methods vs. Subs
Is there anything that you can do with a sub (first parameter being some sort of object) that you cannot do with a method? Frex, given: multi method my_method($invocant:); would topical_call := my_method.assuming :invocant$_; be legal? -- Jonathan Dataweaver Lang
Re: Methods vs. Subs
On Sat, Jul 08, 2006 at 07:42:06AM -0700, Jonathan Lang wrote: : Is there anything that you can do with a sub (first parameter being : some sort of object) that you cannot do with a method? Frex, given: : : multi method my_method($invocant:); : : would : : topical_call := my_method.assuming :invocant$_; : : be legal? Yes, it's certainly legal, but it's not quite the same semantics. A sub guarantees at compile time exactly which routine is going to be called. Your example would need a ::= to do that. But even with that it doesn't really guarantee which my_method you're going to get, in the sense that .assuming is going to have to do a partial method dispatch, and which method it finds will depend on the value of $_. Furthermore, ::= would force that to mean the compile-time value of $_, which is probably not what you want anyway. As far as I can figure, there's no way of defining topical_call such that it knows to .assume $_ as its invocant without actually evaluating $_ at the time .assuming is called, since .assuming doesn't merely set the default; it's a partial dispatch, and throws away the assumed parameter slot entirely from the viewpoint of the subsequent caller. It may well have to keep track of the slot for implementation, however--as a partial dispatch, topical_call may in fact represent a set of remaining candidates to be multi dispatched, and merely setting one parameter with .assuming shouldn't imply that that's the entire eventual parameter list. That is, it mustn't assume that the supplied parameters are delimited with semicolons in the receiving signature. So for purposes of implementation, it does behave merely like a default. Go figure... Larry
Interesting Paper on Prototype Based OO w/ Multi-Methods
Hello All, Recently on #perl6 putter found the Slate language (http://slate.tunes.org/) in our search for some information about Smalltalk. Slate is a prototype based OO language which uses multi method dispatch instead of more traditional method dispatch. As I flipped through some of the papers on the site, I couldn't help thinking back to some of the more recent musing of Larry on the Perl 6 object model. The paper which is most complete is this one: http://tunes.org/~eihrul/ecoop.pdf Or for those with shorter attention spans, there are some slides which give a high level overview of what is in the paper. That can be found here: http://tunes.org/~eihrul/talk.pdf I think there is definitely some valuable information to be found in here, which we can use in the further development of the Perl 6 obejct model. Stevan
Re: Class methods vs. Instance methods
[EMAIL PROTECTED] wrote: : class Dog { : method tail { brown and short } : }; : : class Chihuahua is Dog { : has $.color; : method tail { $.color _ and short } : }; : : You can say Dog.tail, Dog.new.tail, Chihuahua.new.tail, but not : Chihuahua.tail. That's extremely counter-intuitive. I don't think it's counterintuitive. You've defined Dog with an invariant .tail but not Chihuahua. It's doing exactly what you asked for under a prototype view of reality. Except there are no such things as classes in a prototype view of reality. Everything is an instance and there are no such things as class methods. The entire idea that an object (::Dog) can call methods that are for another object ($fido) is ... well ... it's a little off. That's like saying any object can call any method from any other object so long as that method is invariant. In a prototype-instance system, instance(Dog) isa class(Dog) instance(Chihuahua) isa class(Chihuahua) isa class(Dog) instance(Chihuahua) isa instance(Dog) Note that instances inherit doubly, from own class and from parent's instance. But this does not imply that: class(Chihuahua) isa instance(Dog) So I don't see a problem. Miro
Re: Class methods vs. Instance methods
On 1/19/06, Matt Fowles [EMAIL PROTECTED] wrote: Could you provide a concrete example of the advantage of this approach please? Failing that can you try and expand on your gut feeling a bit? May or may not be of use, but Larry's view sounds a bit like reconcilling the (again considered irreconcilable) gap between nominal and structural subtyping: http://cakoose.com/wiki/type_system_terminology#13 Where the empty class object is the degenerate case of the smallest possible structural type, so it can be fulfilled by anything more structurally rich as long as they share the same nominal constraint. Audrey
Re: Class methods vs. Instance methods
On 1/18/06, Audrey Tang (autrijus) [EMAIL PROTECTED] wrote: http://cakoose.com/wiki/type_system_terminology#13 Any practical programming language with structural subtyping will probably let you create and use aliases for type names (so you don't have to write the full form everywhere). However, the underlying type system will only consider the structure of the type when doing its job. What's wrong with Perl doing things that way? duck-typing with names ... sounds like a plan to me ... Rob
Re: Class methods vs. Instance methods
Rob Kinyon wrote: Any practical programming language with structural subtyping will probably let you create and use aliases for type names (so you don't have to write the full form everywhere). However, the underlying type system will only consider the structure of the type when doing its job. What's wrong with Perl doing things that way? duck-typing with names ... sounds like a plan to me ... The thing is that people using .does(Name) and .isa(Name) is probably expecting a nominal answer, not a structural one. Although I do think Visual Basic's explicit duck-subtypes makes a lot of sense: my subset Duck where { has $.half_life; can doom:(); can quake:(-- Wolfenstein); }; then you can apply it as a ducktype with names: my Duck $donald = some_function(); $donald.quake; # assured to return a Wolfenstein object It's already part of S12, by the way. Audrey signature.asc Description: OpenPGP digital signature
Re: Class methods vs. Instance methods
On Thursday 19 January 2006 06:48, Rob Kinyon wrote: Any practical programming language with structural subtyping will probably let you create and use aliases for type names (so you don't have to write the full form everywhere). However, the underlying type system will only consider the structure of the type when doing its job. What's wrong with Perl doing things that way? duck-typing with names ... sounds like a plan to me ... Accidental structural equivalence is a problem -- it's one of the things wrong with C's so-called type system, for example. I like to think of roles as nominally-tagged (and checked) structural subtyping. When you're *defining* a type, its structure matters. When you're *using* it, its behavior matters. It would be nice to keep those two separate. -- c
Class methods vs. Instance methods
Today on #perl6, Audrey, Stevan and I were talking about $repr. A tangent arose where Audrey said that the difference between class methods and instance methods was simply whether or not the body contained an attribute access. Is this true? If it is, then I think it violates polymorphism as demonstrated by the following: class Dog { method tail { brown and short } }; class Chihuahua is Dog { has $.color; method tail { $.color _ and short } }; You can say Dog.tail, Dog.new.tail, Chihuahua.new.tail, but not Chihuahua.tail. That's extremely counter-intuitive. I think that class methods should be explicitly defined as class methods and you cannot call a class method upon an instance, just as you cannot call an instance method upon a class. Plus, this should be determinable (for the most part) at compile time, which is a bonus, imho. Thanks, Rob
Re: Class methods vs. Instance methods
On Wed, Jan 18, 2006 at 01:56:53PM -0500, Rob Kinyon wrote: : Today on #perl6, Audrey, Stevan and I were talking about $repr. A : tangent arose where Audrey said that the difference between class : methods and instance methods was simply whether or not the body : contained an attribute access. : : Is this true? If it is, then I think it violates polymorphism as : demonstrated by the following: : : class Dog { : method tail { brown and short } : }; : : class Chihuahua is Dog { : has $.color; : method tail { $.color _ and short } : }; : : You can say Dog.tail, Dog.new.tail, Chihuahua.new.tail, but not : Chihuahua.tail. That's extremely counter-intuitive. I don't think it's counterintuitive. You've defined Dog with an invariant .tail but not Chihuahua. It's doing exactly what you asked for under a prototype view of reality. : I think that class methods should be explicitly defined as class : methods and you cannot call a class method upon an instance, just as : you cannot call an instance method upon a class. Plus, this should be : determinable (for the most part) at compile time, which is a bonus, : imho. I believe this is already determinble at compile time for the most part. But I have a strong gut-feeling that over the long term it's going to be important to be able to view a given object as either a partially instantiated class or a partially undefined object, and for that we have to break down the false class/instance dichotomy. And to the extent that the dichotomy *isn't* false, we're trying to sweep classness into the .meta object, which is the *real* class object in Perl 6. Larry
Re: Class methods vs. Instance methods
Larry~ On 1/18/06, Larry Wall [EMAIL PROTECTED] wrote: But I have a strong gut-feeling that over the long term it's going to be important to be able to view a given object as either a partially instantiated class or a partially undefined object, and for that we have to break down the false class/instance dichotomy. And to the extent that the dichotomy *isn't* false, we're trying to sweep classness into the .meta object, which is the *real* class object in Perl 6. Perhaps I am just being short sighted, but I never saw this as a false dichotomy. In fact, every time I hear about these partially instatiated I cringe in horror about the strange halfway lands we might end up in... Oh no, this method can only be called on an object that is 3/4 initialized, and you supplied one that is 2/3 initialized that causes undefined behavior. Could you provide a concrete example of the advantage of this approach please? Failing that can you try and expand on your gut feeling a bit? Thanks, Matt -- Computer Science is merely the post-Turing Decline of Formal Systems Theory. -Stan Kelly-Bootle, The Devil's DP Dictionary
Re: Class methods vs. Instance methods
On 1/18/06, Larry Wall [EMAIL PROTECTED] wrote: On Wed, Jan 18, 2006 at 01:56:53PM -0500, Rob Kinyon wrote: : Today on #perl6, Audrey, Stevan and I were talking about $repr. A : tangent arose where Audrey said that the difference between class : methods and instance methods was simply whether or not the body : contained an attribute access. : : Is this true? If it is, then I think it violates polymorphism as : demonstrated by the following: : : class Dog { : method tail { brown and short } : }; : : class Chihuahua is Dog { : has $.color; : method tail { $.color _ and short } : }; : : You can say Dog.tail, Dog.new.tail, Chihuahua.new.tail, but not : Chihuahua.tail. That's extremely counter-intuitive. I don't think it's counterintuitive. You've defined Dog with an invariant .tail but not Chihuahua. It's doing exactly what you asked for under a prototype view of reality. Except there are no such things as classes in a prototype view of reality. Everything is an instance and there are no such things as class methods. The entire idea that an object (::Dog) can call methods that are for another object ($fido) is ... well ... it's a little off. That's like saying any object can call any method from any other object so long as that method is invariant. : I think that class methods should be explicitly defined as class : methods and you cannot call a class method upon an instance, just as : you cannot call an instance method upon a class. Plus, this should be : determinable (for the most part) at compile time, which is a bonus, : imho. I believe this is already determinble at compile time for the most part. But I have a strong gut-feeling that over the long term it's going to be important to be able to view a given object as either a partially instantiated class or a partially undefined object, and for that we have to break down the false class/instance dichotomy. And to the extent that the dichotomy *isn't* false, we're trying to sweep classness into the .meta object, which is the *real* class object in Perl 6. I'm sure you understand the distinction you're making. I know I don't and I've been trying to follow this discussion for the past year. I'm may not be the brightest bulb in the chandelier, but I'm no 15W dimmer switch, either. Frankly, you should be using people like me, Matt Fowles, and the other programmers on the list as sounding boards. If we're having problems understanding the concept, then how are we going to explain partially-instantiated classes on Perlmonks or #perl or clmp? Like it or not, we're the sergeants in the Perl army. We're the guys explaining all this stuff to the privates coming up the ranks. It may be a nice extension to have, but I'm not sure this should be part of the standard MOP. Rob
Re: private methods and role composition
On Sat, Nov 05, 2005 at 11:35:38AM -0800, Jonathan Lang wrote: : First off: is there a way to declare a method as being private to a role? We're still batting around the notion of private methods. Certainly with a lexically scoped sub you can get most of the same benefit. Trust could then perhaps simply be exportation of the sub to another scope, though naming another lexical scope is problematic, and if you export into a package the name becomes public property. So the import needs to be into a different lexical scope that happens to be governed by a particular trusted class name. Lexically scoped methods or submethods are also a syntactic possibility: my method foo {...} my submethod BUILD {...} If this is how you write private methods, though, these have to be totally invisible to the ordinary dispatcher. And just as has defaults to private in the absence of a twigil, perhaps it does on methods too: has $foo; # short form private has $!foo; # long form private (but same variable as $foo) has $.foo; # public virtual interface to private $!foo has method foo; # short form private? has method !foo;# long form private? has method .foo;# public? same as method foo But that's a little strange--has should probably indicate that each object maintains its own copy. Maybe it's really the underlying delegation mechanism: has method foo = some_other_foo(); # init at BUILD time So probably my is still better for private methods, and tends to keep weirdness out of the package's public interface. It would be nice if the package only contains public method names and private metadata is confined to the meta object (whether class or proto based). : Second: can a role reclassify as private a method that is composed : into it from another role? I don't see much point. Private methods are non-virtual, and shouldn't be inherited, or block the inheritance of anything public. Private methods are really just subs in disguise. We allow them to be called with something resembling ordinary dispatch syntax (probably via $!foo and $obj!foo() these days) but the public and private dispatch mechanisms have no overlap. Larry
private methods and role composition
First off: is there a way to declare a method as being private to a role? Second: can a role reclassify as private a method that is composed into it from another role? -- Jonathan Dataweaver Lang
Re: Custom Metaclass and Inheritance of Class Methods
== CONCLUSION / WRAP-UP So, now that I have sufficiently bored you all to tears, I will do a quick re-cap of the main question, and the possible solutions. Should metaclasses be inherited along normal class lines? Meaning that if Foo uses a custom metaclass, and Bar isa Foo, then Bar also uses that metaclass. If we say yes, then I think it is clear that in order to get a sane method and predictable resolution order the custom metaclass would always need to precede the inherited eigenclass in the superclass list. (see the last example above). If we say no, then we need to introduce another anyonomous class into our mix, which we call an 'x' class. The 'x' class would need to use a breath-first dispatch order in order to produce a sane and predictable method resolution order. I would like to expand on my position in the discussion Steve and I had, which is the no position. The crux of my view is that Foo is an instance of some custom metaclass. Bar is an instance of Class (for the sake of argument). Foo and Bar are unrelated, save for the fact that instances created by Bar's new() function will have access to all the behaviors and state that instances created by Foo's new() function will have. This is why I also feel that class methods shouldn't have the same MRO as instance methods, but that's a moot discussion. Rob
Custom Metaclass and Inheritance of Class Methods
Hey All, So, given the abundance of positive responses ;) for my class methods don't inherit proposal, I have decided to withdraw that proposal (see my last response on the thread). Of course, this means we now have to work out the details of exactly *how* they get inherited in all situations. The trickiest one being in the presence of custom metaclasses. So, onto the questions. (NOTE: if you get bored about half-way through this mail (and you probably will), there is a conculsion/wrap-up at the very bottom that you can probably safely skip ahead too) Should custom metaclasses are inherited along normal subclass lines? This would mean that if Foo uses CustomMeta as it's metaclass, any subclass of Foo will do the same. This is something Larry mentioned, and something I had been thinking about a lot myself and discussed recently with Rob Kinyon. I drew a diagram in my response to Larry that looked like this: Class ^ : CustomMeta ^ : eFoo...eBar ^ ^ | | Foo...Bar This shows the structure which would be created. The result is that method dispatch would go like this: Bar.foo eBar.get_method(foo) eFoo.get_method(foo) CustomMeta.get_method(foo) Class.get_method(foo) ! No Method Found Error ! I think this makes sense in many ways since CustomMeta can theoretically add capabilities to the Foo class, which one would want inherited by subclasses of Foo. (NOTE: if CustomMeta adds instance methods to Foo, they will get inherited, mostly I am talking about class functionality here) However, I can also see where it would make sense for this *not* to behave this way. But if we the opposite approach, the eigenclass/ metaclass hierarchy begins to get more complex. To start with, we would need to create another anon-class (called xFoo here) which uses multiple inheritence to inherit from eFoo and CustomMeta, then eBar would inherit from eFoo (and through eFoo, to Class), this would keep CustomMeta out of Bar's method dispatch path. Class ^^... : : CustomMeta : ^ : : : xFoo...eFoo...eBar ^ ^ | | FooBar The resulting method dispatch paths would be: Bar.foo eBar.has_method(foo) eFoo.has_method(foo) Class.has_method(foo) ! Method Not Found Error ! Note the lack of CustomMeta in the dispatch path, where as in the above example it was there. This on it's own is not too bad, however, when we add another metaclass, it starts to get busier. Our anon-class xBar must inherit from eBar and CustomMeta2 (just like xFoo did). Then eBar must be connected to eFoo in order to inherit from it, but not pic up any of CustomMeta's methods. Class... ^^... : : : : CustomMeta :CustomMeta2 ^ : ^ : : : xFoo...eFoo xBareBar ^ ^ ^: | :.|: | | Foo..Bar The method dispatch path for this is pretty much the same as above, with the addition of CustomMeta2. This example now actually brings up another issue. What should the superclass ordering be within the x* classes? If eBar comes first, followed by CustomMeta2, then we get the following method dispatch path: Bar.foo xBar.has_method(foo) # xBar should never have any of it's own method eBar.has_method(foo) eFoo.has_method(foo) CustomMeta2.has_method(foo) # this would fall here under C3 Class.has_method(foo) ! Method Not Found Error ! But if CustomMeta2 comes first, followed by eBar, then we get the following method dispatch path: Bar.foo xBar.has_method(foo) CustomMeta2.has_method(foo) eBar.has_method(foo) eFoo.has_method(foo) Class.has_method(foo) ! Method Not Found Error ! The question really is, which has precedence, the custom metaclass, or the local class methods (including class methods inherited along normal class lines)? Now, all these method dispatch paths are using the C3 MRO. And personally I find neither of these approaches to be the best. One alternate (but kind of whacky) approach would be to not use C3 here, but instead use breath-first traversal. Now, this may seem really odd at first, but given the highly regular structure of these class groupings, it might make the most sense. Here is what that method dispatch path might look like: Bar.foo xBar.has_method(foo) eBar.has_method(foo) CustomMeta2.has_method(foo) eFoo.has_method(foo) Class.has_method(foo) ! Method Not Found Error ! Notice how the eBar (which hold's Bar's class methods) is first, followed by the CustomMeta2 class, the followed by eFoo, then onto Class. This specialized dispatching behavior could (I
Class Methods, Eigenclasses and $?CLASS
Evening all, So I am in the process of adding class-methods into the meta-model using eigenclasses. Eigenclasses are a ruby thing (and also a CLOS thing IIRC), in which an anon-class is inserted between an instance and it's class, essentially replacing the instance's class. The anon- class then adds the original class to it's superclass list. This is best shown visually I think: ::Class ^ : -- eFoo is a subclass of Class : ::eFoo # eFoo is also an instance of Class | | -- eFoo is the class of Foo V ::Foo The dispatching of instance methods is still the same, and everything just works. Well... almost everything. There is a slight issue/inconsitency with how $?CLASS works. class Foo { method bar (Class $c:) { $?CLASS } method baz (Foo $self:) { $?CLASS } } Within the bar class-method, the natural inclination is to think that $?CLASS will refer to ::Foo. However, in order to be consistent it actually refers to the eigenclass between ::Foo and ::Class, lets call it ::eFoo. This is because methods are associated with the class which contains them. In the baz instance-method, $?CLASS does refer to ::Foo, since ::Foo is the class which contains baz. It seems to me that this inconsistency could be very problematic, especially since eigenclasses should really be an invisible implementation detail. I am not 100% sure of what is the correct approach here, so I thought I would ask the group. Any thoughts guys/gals? Thanks, Stevan
Re: Class Methods, Eigenclasses and $?CLASS
On 10/10/05, Stevan Little [EMAIL PROTECTED] wrote: ::Class ^ : -- eFoo is a subclass of Class : ::eFoo # eFoo is also an instance of Class | | -- eFoo is the class of Foo V ::Foo The dispatching of instance methods is still the same, and everything just works. Well... almost everything. How do you explain this: class Foo { method bar (Class $class:) { class method } } say Foo.bar;# class method my $foo = Foo.new; say $foo.bar; # class method Assuming that that is valid Perl. Luke
Re: Class Methods, Eigenclasses and $?CLASS
Luke, On Oct 10, 2005, at 7:47 PM, Luke Palmer wrote: How do you explain this: class Foo { method bar (Class $class:) { class method } } say Foo.bar;# class method my $foo = Foo.new; say $foo.bar; # class method Assuming that that is valid Perl. It is valid Perl 5, however (IMHO) it is *not* valid Perl 6. To start with, the type of the invocant is Class, which $foo is not derived from (it is an instance of something which itself is an instance of Class). I think that $foo.class.bar() should work. And changing the method defintion to be method bar (Class|Foo $class:) { ... } should work, but the code as you wrote it should not. Which means that when we deal with Perl 5 classes within Perl 6, we should likely give them an implied signature of (Class|Foo $self:) or some other weirdness (I haven't thought that far down the line yet). Class methods are strange creatures, in Perl 5 they were nothing different than instance methods. In Java (static methods), they are really just odd functions which need to be qualified by a class name. Python doesn't even really have them (you have to jump through odd hoops to make the method callable). Ruby uses Eigenclasses, and CLOS uses something akin to eigenclasses. I am not sure how Smalltalk handles things, but my guess is that class methods on Foo are instance methods of classFoo, or some such. They are ugly beasties no matter what, but eigenclasses (so far) seem to be the prettiest of the uglies. Stevan