RFC 101 (v3) Apache-like Event and Dispatch Handlers
This and other RFCs are available on the web at http://dev.perl.org/rfc/ =head1 TITLE Apache-like Event and Dispatch Handlers =head1 VERSION Maintainer: Nathan Wiger <[EMAIL PROTECTED]> Date: 14 Aug 2000 Last Modified: 25 Sep 2000 Mailing List: [EMAIL PROTECTED] Number: 101 Version: 3 Status: Frozen =head1 ABSTRACT A complete Perl 5 implementation of this can be found as Class::Handler http://www.perl.com/CPAN/authors/id/N/NW/NWIGER/Class-Handler-1.03.tar.gz Currently, there is no way to have multiple methods or modules for dealing with events without significant contortions: $data = $r1->get_data || $r2->stuff || $r3->func; $r1->do_stuff(@vals) or $r1->do_this(@vals); These simple cases can actually be tolerated. However, there are many more complex cases which cannot be handled at all in Perl. These include opening files only in certain directories, having methods decline or partially handle requests, and so on. This RFC proposes the idea of a C, which is a special type of class that is actually composed of one or more classes. Their operation is very similar to Apache handlers: requests can be handled, declined, or partially handled, without the top-level program having to know about it. =head1 NOTES ON FREEZE The only concern ever raised was on why this should be core-worthy. One word: speed. Currently, it can be implemented via C, but this is slow. Also, other RFCs such as B rely on the notion of handlers to gain important functionality (such as the ability to transparently open URLs and different file types). Damian has a separate RFC on pre and post sub handlers. It may be possible to integrate the two into a common handler framework/methodology. Unfortunately, I don't think either of us has the time to do this at this point because of the upcoming RFC deadline. However, this is something that should definitely be looked into in the future. =head1 DESCRIPTION =head2 Overview The concept of a C is actually not that complex. In the simplest case, it can be thought of as a type of abstraction: sub open_it { my $file = shift; return open $file || HTTP::open $file || FTP::open $file; } Then, in your script, you would simply say: $fileobject = open_it "< $filename"; This gives you several benefits: 1. The internal handling of open_it can be changed without having to update all your programs 2. Each operation can actually partially process the request, if appropriate 2. Your program is easier to read and understand >>From a Perl standpoint, these handlers work just like normal functions and classes: they have methods, properties, inheritance, and so forth. The only difference is that these handlers do not live in an external file, but rather are assembled internally by Perl. =head2 Adding and Using Handlers First, the examples assume that the reader is somewhat familiar with RFC 14. If not, it is recommended that you give it a quick read at http://dev.perl.org/rfc/14.pod There are several competing syntaxes that I have for this proposal. I've provided the one that I think is the best, but this is open to discussion. The proposed syntax is to use a pragmatic style: use handler 'http' => 'MyHTTP'; use handler 'http' => 'LWP::UserAgent'; This would assemble a C called 'http' which could then be used in functions in your program. This handler would be a pseudo-class that inherits methods from C and C, in that order. So: $fo = open http "http://www.yahoo.com" or die; would call Copen>, consistent with the current Perl implementation. The only difference would be that C now tries to call the C method from C and C. As such, the above call would result in the following flow chart: $fo http->openundef ^ | ^ | | | | Does MyHTTP::open exist?| |YES/ \NO | | / \ | | Try it Does LWP::UserAgent::open exist? | | / \^ YES/ \NO | |OK/ \UNDEF / / --- -- Try it| | / \ | | OK/\UNDEF | - - Some highlights: 1. Each class's open() method is tried in turn. 2. If undef is returned, the next one in sequence is tried. 3. If 'OK' (simply meaning 1 or some other true value, like $fo) is returned, that is propagated out and returned by the top-level handler. 4. All classes are tried until 'OK' is returned or the last one is reached. This allows you to easily chain classes and methods together with a couple key benefits over an inline C<||>: 1. E
RFC 319 (v1) Transparently integrate C
This and other RFCs are available on the web at http://dev.perl.org/rfc/ =head1 TITLE Transparently integrate C =head1 VERSION Maintainer: Nathan Wiger <[EMAIL PROTECTED]> Date: 25 Sep 2000 Mailing List: [EMAIL PROTECTED] Number: 319 Version: 1 Status: Developing =head1 ABSTRACT B proposes many enhancements to C to make it more versatile and multipurpose. However, it still relies on using the C keyword to create a Cd variable, keeping C separate. Python and lots of other languages have figured out how to implement fully-integrated data, operator, and method overloading. Perl should too, without looking horrendously OO-ish like Python. =head1 DESCRIPTION =head2 Implicit C This RFC proposes that C be integrated with Perl from the ground up, and not remain as a separate concept. Instead, classes that provide C methods will have them automatically invoked on assignment. For example: my bigint $x = 5; # bigint->TIESCALAR($x); $x->STORE(5); The C methods are called implicitly on I. So: my packed $a; # just an assertion, RFC 218 $a = get_binary;# packed->TIESCALAR($a); $a->STORE(..); $a = more_data; # $a->STORE(...); $a++; # $a->STORE($a->PLUS(1)); undef $a; # $a->DESTROY; my int @b :64bit; # again, just an assertion @c = @b;# empty list passed still @b = (1,2); # int->TIEARRAY(@a, '64bit'); @b->CLEAR(...); ... Note that the C methods will only be called if they exist, just like currently. If a given C method does not exist, then the appropriate error should be spit out: my Pet @spot = ("fluffy"); Can't locate method "TIEARRAY" via package "Pet" In this case, the package C has declared that it can't handle arrays, which is just fine. =head2 Optimization and Inheritance One of the main goals behind doing something like this is being able to create custom variable types that can take advantage of optimizations, and having these variables walk and talk like builtins. For this reason, it is further proposed that all variable types be handled through basic method inheritance in Perl 6. Essentially, everything becomes an object and is fully overrideable and redefineable. So, for example: package var; # main variable class # all the main Perl internal methods are defined, such # as TIESCALAR, TIEARRAY, STORE, FETCH, etc package int; use base 'var'; # ideas for RFC 303 use optimize storage => 16, # how much space growable => 1, # can we grow? growsize => 8, # how much to grow by integer => 1,# support ints string => undef, # but not strings float => undef, # or floats promote => 'bigint'; # promote to class # when outgrow # TIESCALAR, STORE, etc need not be redefined, since # they could simply inherit from var's, but perhaps # we could define special math ops per RFC 159. In this example, we've used the C class to define several key optimizations for Perl to use. Since C is the grandfather class of all variables, its C and C methods can be used, which actually do the internals of storing values and using the hints set by the C pragma. In reality, builtin types will be implemented in C and not Perl. However, that doesn't mean that other custom classes couldn't still inherit from these types as well. For example: package CoolInt; # my own, real cool int use base 'int'; # setup all my methods and optimizations So, dispatch for builtin types could be very fast - the correct C et al methods (written in C) are simply called. Then, user-defined types would be derivable from builtin types with some slowdown, but nowhere near as bad as C. Code could simply look like this: use CoolInt; my CoolInt $x = 42; # CoolInt->TIESCALAR($x); $x->STORE(42); Thus making it transparent to the user, and not requiring either of these: # Use our constructor my $x = CoolInt->new(42); # Use a tie interface tie CoolInt $x; $x = 42; =head2 Type checking Nat's upcoming RFC on type checking will propose a C pragma. Type checking would be trivial to implement by combining aspects of this RFC with the C concept: package Pet : interface; # RFC 265 use optimize types => ['Dog', 'Cat']; With this declaration, Perl is now told that anything of type C can be either a C or a C. This means that in your main code: use strict 'types'; my Pet $spot = new Camel; # oops! The second line would raise a syntax error. =head2 The C<:tie> attribute Making C this seamless may scare some people. In this case, we may wish to add an C<:tie> attribute that can be specified on the C: package Pet : tie; # will be auto-tied Placing this on the package, and not individual subs, makes more sense because it dictates how all the package's methods interact. The idea here is that by fully integra
Re: Pulling RFC 161
Bennett Todd wrote: > > If the only grounds is lack of interest, please just freeze it. It > can be tossed later if people turn up strong counterarguments, like > difficulting keeping the language's semantics intact or difficulty > delivering better performance than perl5. I agree. I haven't heard any counterarguments other than speed. If any of the -internals claims hold up, that won't even be an issue, in which case this is a good idea. -Nate
Re: RFC 307 (v1) PRAYER - what gets said when you C something
> This RFC proposes a special sub, C, which is automatically called > on Cing. Damian already covered this issue very thoroughly in RFC 189: "Hierarchical calls to initializers and destructors". -Nate
Re: RFC 307 (v1) PRAYER - what gets said when you C something
RFC 189 covers this. Damian
RFC 307 (v1) PRAYER - what gets said when you C something
This and other RFCs are available on the web at http://dev.perl.org/rfc/ =head1 TITLE PRAYER - what gets said when you C something =head1 VERSION Maintainer: Simon Cozens <[EMAIL PROTECTED]> Date: 25 Sep 2000 Mailing List: [EMAIL PROTECTED] Number: 307 Version: 1 Status: Developing =head1 ABSTRACT This RFC proposes a special sub, C, which is automatically called on Cing. =head1 DESCRIPTION The abstract more or less says it all, but this is more than just a joke. Suppose, for instance, your class needs to do some initialisation whenever a new object is created; C would be where the class initialisation takes place. There's also the more interesting and (IMHO) important issue of reblessing; that is, changing the class of an object. There are times when you want to do this, but it's hairy because you have to know the workings of both classes. However, if you have C called automatically on Cing, you can automagically "cast" objects between classes. For instance, an object in class X would get changed to an object in class Y with bless $obj, "Y"; Perl would then perform the reblessing and call: package Y; sub PRAYER ($object, $oldclass) { if ($oldclass eq "X") { ... } else { die "Can't cast an $oldclass to a Y"; } } You may also use this method as a form of "pre-constructor", or even, on simple enough classes, a constructor proper. Maybe subs to cast between classes should somehow be shared between the two classes; the special sub C would be the obvious place for that. =head1 IMPLEMENTATION Adding a method call to the end of C should not be tricky. =head1 REFERENCES None.
RFC 218 (v2) C is just an assertion
This and other RFCs are available on the web at http://dev.perl.org/rfc/ =head1 TITLE C is just an assertion =head1 VERSION Maintainer: Piers Cawley <[EMAIL PROTECTED]> Date: 13 Sep 2000 Last Modified: 25 Sep 2000 Mailing List: [EMAIL PROTECTED] Number: 218 Version: 2 Status: Frozen =head1 ABSTRACT The behaviour of the syntax should simply be an assertion of the invariant: (!defined($spot) || (ref($spot) && $spot->isa('Dog))) =head1 NOTES ON THE FREEZE The original version of this attracted very little comment and what there was was positive. Therefore I've frozen it as it stands. =head1 DESCRIPTION The syntax my Dog $spot = Dog->new(); currently carries little weight with Perl, often failing to do what one expects: $ perl -wle 'my Dog::$spot; print "ok"' No such class Dog at -e line 1, near "my Dog" Execution of -e aborted due to compilation errors. $ perl -wle 'sub Dog::new; my Dog $spot; print "ok"' ok $ perl -wle 'sub Dog::new; my Dog $spot = 1' ok The first example is obvious, as is the second. The third one is I. I therefore propose that C comes to mean that C<$spot> is restricted to being either undefined or a reference to a C object (or any subclasses of Dog). Simply having this implicit assertion can be useful to the programmer, but I would argue that its main advantage is that the compiler knows the object's interface at compile time and can potentially use this fact to speed up method dispatch. =head2 Examples In class methods: package Dog; sub speak { my Dog $self = shift; # Sadly 'my __PACKAGE__ $self' doesn't work print $self->name, " barks!\n"; } Admittedly, this makes little sense unless there is some optimization available, but it can still be useful as a notational convenience. Or, consider the case where you have an C object and you're looking to get a Dog from there. my AnimalShelter $shelter = RSPCA->find_nearest_shelter; my Dog $stray; try { PET: while (!defined($stray)) { $stray = $shelter->next_animal; } } catch Exception::WrongClass { next PET; } $stray->bark; Admittedly this makes some assumptions about the possibility of loops within try blocks, but I think the point is still valid. My main concern with this proposal is to make it possible to use the C syntax along with it's associated (posited) optimizations and assertions wherever it's appropriate in user code. =head1 IMPLEMENTATION I've not really looked into using source filters, but if C can be mapped to C then Tie::Invariant can look something like: package Tie::Invariant; use carp; sub TIESCALAR { my $self = bless {value => undef}, shift; $self->{class} = shift; return $self; } sub FETCH { my $self = shift; return $self->value; } sub STORE { my($self,$newval) = @_; if (!defined($newval) || (ref($newval) && UNIVERSAL::isa($newval, "UNIVERSAL") && $newval->isa($self->{class}))) { croak "Value must be 'undef' or be a $self->{class}" } $self->{value} = $newval; } Note that the above is merely a sample implementation written in Perl5. I would hope that the 'real' code would be within the perl5 interpreter and compiler. And all the faster for that. =head1 MIGRATION Migration issues should be minor, the only problem arising when people have assigned things that aren't objects of the appropriate type to typed variables, but they deserve to lose anyway. =head1 REFERENCES RFC 171: my Dog $spot should call a constructor implicitly This RFC is a counter RFC to RFC 171. See my forthcoming 'new pragma: use package' RFC for something that addresses one of the concerns of RFC 171. RFC 137: Overview: Perl OO should I be fundamentally changed My guiding principle.
RFC 265 (v2) Interface polymorphism considered lovely
This and other RFCs are available on the web at http://dev.perl.org/rfc/ =head1 TITLE Interface polymorphism considered lovely =head1 VERSION Maintainer: Piers Cawley <[EMAIL PROTECTED]> Date: 20 Sep 2000 Last Modified: 25 Sep 2000 Mailing List: [EMAIL PROTECTED] Number: 265 Version: 2 Status: Developing =head1 ABSTRACT Add a mechanism for declaring class interfaces with a further method for declaring that a class implements said interface. There should be (at least) runtime checking to ensure that a class actually *does* implement said interface, with an option to have compile time checks made. =head1 CHANGES =over 4 =item Notes I've tried to add [Note ...] lines in bits where I need some further input to try and nail the RFC down. =item More compile time errors It's now a compile time error if an interface file tries to do anything other than pre declare methods. =item Added a reference to RFC 193 C. =item Removed the 'too ugly to live' :must(Foo) suggestion. I didn't like it, Damian didn't like it, and it was Damian's idea. So it's gone. =back =head1 DISCUSSION =over 4 =item * Damian points out that the distinction between C and C don't need to be distinguished. I believe that, although it may be the case that there's no need to make the distinction in the internals of perl, the distinction is a useful mnemonic one for the programmer, and (I think) separating the different meanings into different pragmata potentially simplifies the implementation of both of 'em. He also further points out that C isn't strictly necessary. I counter that it may not be necessary, but it'd be a simple pragma module to write and would again serve to help clarify the programmers intent. =back =head1 DESCRIPTION =head2 Rationale To (mis)quote Damian Conway "Inheritance polymorphism proliferates pretend classes". The idea is that C will eventually give us some real performance gains, so more folks will want to use it. But this leads to a proliferation of 'ghost' base classes that are simply there to provide a handle for C optimization. So, I propose that we move such classes sideways and make them into first class interfaces. By supporting interface polymorphism the way is opened for adding more stricture in projects that *need* it, as well as allowing for the possibility of compile time optimization for classes that use the interface structure. =head2 Syntax My current thought is that an interface file would look something like: interface Fetcher; sub fetch; Note the new keyword, interface, this works just like package but with the restriction that it can only contain subroutine declarations. A Class that implements the interface would then look like: package TrainedCat; use strict 'implementation'; use strict; use base 'Cat'; use interface 'Fetcher'; sub fetch { my TrainedCat $self = shift; my $thing = shift; return $self->can_lift($thing) ? $thing : undef; } Note the C, this declaration implies that interface conformance shall be checked at compile time. If the C class doesn't implement the C interface in full then compilation shall fail. Without this stricture constraint the compiler shall throw a warning. If an interface file contains anything but forward subroutine declarations the compiler shall throw an error. [NOTE: What about interface inheritance hierarchies, thoughts please] Of course, Perl being Perl and all lovely and dynamic, there's a good chance that some of the methods that implement the interface aren't actually compiled up at the end of the compilation phase. Therefore we have: package LazyDog; use strict 'implementation'; use interface 'Fetcher'; use deferred qw/fetch/; ... sub AUTOLOAD { ... *fetch=sub {...}; goto &fetch; ... } C informs the compiler that the method will be available when it's needed, even if it isn't actually in the symbol table/class hierarchy just yet. In client code, lexicals that are typed into interfaces only require that the objects assigned to them satisfy the interface. ie. They don't care about an objects class, they just care what it can do. (If only life were like that...) use strict 'interfaces'; my Fetcher $x; my Dog $spot; my NetSnarfer $z; my $method = 'fetch'; # Compile time stuff $x = $z;# ok because $z can fetch $x = $spot; # ok because $spot can fetch $x->fetch();# ok because Fetcher->can('fetch'); $x->bark(); # not ok because ! Fetcher->can('bark'); # Runtime stuff $x->$method(); # ok because Fetcher->can('fetch'); $method='bark'; $x->$method(); # runtime error because ! Fetcher->can('bark') Without the C declaration, these errors get demoted to compile time warnings. Of course, without the stricture any compiler optimizations become somewhat tricky. =head2 Another possible syntax Nathan Torkington suggested another syntax: package Cat implements Pet; package Dog implements Pet; Whic
Re: Pulling RFC 161
2000-09-25-12:04:44 Matt Youell: > Unless I hear compelling arguments to the contrary, I'll be > withdrawing RFC 161 on Tuesday due to lack of interest. If the only grounds is lack of interest, please just freeze it. It can be tossed later if people turn up strong counterarguments, like difficulting keeping the language's semantics intact or difficulty delivering better performance than perl5. But neither of those consequences look obviously foreordained to me, and the proposal very sweetly allows us to bring to bear the object-overloading machinery on adding extensions and customizing the language. I think the proposal is daring and perhaps a bit more extreme than I'd be optimistic about actually getting, but if folks haven't forcibly gunned it down please don't retract it. In the spirit of perl borrowing from other languages, this would be perl borrowing from Ruby:-). -Bennett PGP signature
RFC 256 (v2) Objects : Native support for multimethods
This and other RFCs are available on the web at http://dev.perl.org/rfc/ =head1 TITLE Objects : Native support for multimethods =head1 VERSION Maintainer: Damian Conway <[EMAIL PROTECTED]> Date: 18 September 2000 Last Modified: 25 Sep 2000 Mailing List: [EMAIL PROTECTED] Number: 256 Version: 2 Status: Frozen =head1 ABSTRACT This RFC proposes that Perl natively support multiply dispatched subroutines (multimethods). =head1 DESCRIPTION Multimethods solve a class of problems in which objects of two or more hierarchies must interact polymorphically, but where the nature of the interaction is determined by the run-time type of I (I) the objects. =head2 Theoretical model It is proposed that calls to certain (explicitly marked) subroutines be dispatched using a different mechanism from that used for regular Perl 5 subroutines, or that used for Perl 5 methods. These explicitly marked subroutines would share the same name, but provide unique parameter lists. Collectively all marked subroutines with the same name but different parameters lists would be known as a I, with each individual subroutine known as a I of the multimethod. The new dispatch mechanism would look at the classes or types of each argument to the subroutine (by calling C on each) and determine the "closest" matching variant of the multimethod, according to the parameter types specified in the variants' parameter list. The result would subsume the behaviour of function overloading (e.g. in C++) but in a more sophisticated manner, since multimethods take the run-time inheritance relationships of each argument into account. Another way of thinking of the mechanism is that it would perform polymorphic dispatch on every argument of a multimethod, not just on the first. =head2 Defining multimethods A single variant of a multimethod would be defined by specifying a subroutine with a full parameter list (as per RFC 128), and appending the attribute C<:multi>. Two or more such subroutines could be defined with the same name, in the same package namespace, provide they were both defined with the C<:multi> attribute, and their parameter lists were not identical. For example: package LargeNum; package LargeInt;use base 'LargeNum'; package LargeFloat; use base 'LargeNum'; package LargeMath; sub divide(LargeInt $a, LargeInt $b) : multi { ... } sub divide(LargeInt $a, LargeFloat $b) : multi { ... } This creates a (single) multimethod called C with two variants. If the multimethod is called with two references to LargeInt objects as arguments: $x = LargeInt->new(1234567890); $y = LargeInt->new(9876543210); $quotient = divide($x, $y); then the first variant is invoked. If the multimethod is called with a LargeInt reference and a LargeFloat reference: $x = LargeInt->new(1234567890); $y = LargeFloat->new(9876543210.12345); $quotient = divide($x, $y); then the second variant is called. Calling the multimethod with any other combination of LargeNum-derived reference arguments (e.g. a reference to a LargeFloat and a reference to a LargeInt, or two LargeFloat references) results in an exception being thrown, with the message: No viable candidate for call to multimethod divide To avoid this, a "catch-all" variant could be specified: sub divide(LargeNum $b, LargeNum $b) : multi { ... } Now, calling C with (for example) a LargeFloat reference and a LargeInt reference causes this third variant to be invoked. That's because a LargeFloat I LargeNum (so the first argument is compatible with the first parameter), and a LargeInt I LargeNum too (so the second argument is compatible with the second parameter). Note that adding this third variant doesn't affect calls to the other two, since multiple dispatch always selects the nearest match. =head2 Finding the "nearest" multimethod The usefulness of multiple dispatch depends on how intelligently the dispatcher decides which variant of a multimethod is "nearest" to a given set of arguments. That decision process is called I, and it is proposed that it be done (or I to be done, modulo optimization) like this: =over 4 =item 1. If the types of the arguments given (as determined by applying C to each in turn) exactly match the set of parameter types specified in any variant of the multimethod, that variant is immediately called. =item 2. Otherwise, the dispatch mechanism compiles a list of viable targets. A viable target is a variant of the multimethod with the same number of parameters as there were arguments passed. In addition, for each parameter the specified parameter type must be a base class of the actual type of the corresponding argument in the actual call (i.e. each argument must belong to a subclass of the corresponding parameter type). =item 3. If there is only one viable target,
RFC 193 (v2) Objects : Core support for method delegation
This and other RFCs are available on the web at http://dev.perl.org/rfc/ =head1 TITLE Objects : Core support for method delegation =head1 VERSION Maintainer: Damian Conway <[EMAIL PROTECTED]> Date: 4 Sep 2000 Last Modified: 25 Sep 2000 Mailing List: [EMAIL PROTECTED] Number: 193 Version: 2 Status: Frozen =head1 ABSTRACT This RFC proposes that Perl 6 offer built-in support (via a pragma) for delegating method calls to attributes of an object. =head1 DESCRIPTION Delegation of method calls to attributes is a powerful OO technique that is not well supported in most OO-capable languages, including Perl 5. Delegation offers most of the advantages of inheritance (and, more particularly, multiple inheritance) without most of the headaches. It also offers some extra features that inheritance cannot provide. The proposed delegation mechanism would work via a pragma: use delegation attr1 => [qw( method1 method2 method3 )], attr2 => [qw( method4 method5 )], attr3 => __ALL__, attr4 => __ALL__, # etc. ; This would cause method calls whose names match an element in the first list to be delegated to the "attr1" attribute of an object. Likewise, calls to a method whose name appears in the second list would be forwarded to the "attr2" attribute of the object. That is, calls like: $obj->method3(@args); $obj->method5(@other_args); would act as if they were: $obj->{attr1}->method3(@args); $obj->{attr2}->method5(@other_args); (and, if these attribute objects also delegated, the process might repeat recursively until some deeply nested attribute actually provided a method to call). Attributes which appear with the string "__ALL__" instead of a method list become "catch-alls". Unresolvable method calls are delegated to the first of these that is able to handle it. So, for example, a call like: $obj->method6(@more_args); would become equivalent to: $obj->{attr3}->method6(@more_args); if $obj->{attr3} had a C method (or an C), or else: $obj->{attr4}->method6(@more_args); if $obj->{attr4} had a suitable method. Unlike explicitly delegated methods, which are delegated on the first method look-up pass, delegation to catch-alls occurs on the second pass, just before the dispatch mechanism tries the package's C method. Note that the presence of one or more catch-all's does not prevent an C being called, if none of the catch-alls can handle the requested method. If the explicit methods, the catch-alls (and any C) all fail to provide a suitable method, the normal dispatch would then continue into the object's ancestral classes (if any). An attribute can appear several times in a C statement, with all its delegation method lists being consolidated. An attribute may also appear both with an explicit delegation list and as a catch-all. For example: use delegation attr1 => [qw(method1 method2)], attr2 => [qw(method3 method4)], attr1 => __ALL__, ; This example specifies that calls to the methods C and C should be delegated to the "attr1" attribute, calls to the methods C and C should be delegated to the "attr2" attribute, and any remaining calls that are not handled before the C pass should be delegated to the "attr1" attribute (if it can handle them). =head2 New dispatch sequence With delegation available, the method dispatch sequence becomes (I): =over 4 =item 1. Look for the named method in current class, I. =item 2. Recursively repeat steps 1 and 2 in ancestral class(es) and in UNIVERSAL. =item 3. Ied in the attribute object's class.> =item 4. Check for C in current class =item 5. Recursively repeat steps 3 to 5 in ancestral class(es) and in UNIVERSAL. =back =head2 Using delegation instead of inheritance One powerful application of delegation is as a replacement for inheritance where the internals of a prospective base class are inaccessible or inconvenient, or the base class was not designed to be inherited and yet it must be. For example, consider the task of creating an IO::File-like class that reads and writes to separate handles: use IO::Bi; my $handle = IO::Bi->new('infile', 'outfile'); if (defined($_ = $handle->getline)) { $handle->print($_); } foreach ($handle->getlines) { $handle->print($_); } IO::Bi can't inherit from IO::File, because it needs two file handles, with input methods going to one and output methods going to the other. That's impossible with inheritance (even using the dreaded "diamond inheritance pattern") because a class can inherit the state of any ancestral class only once, no matter how many paths that ancestor is inherited through. In C++ terms, all inheritance in Perl is "virtual". With delegation, the solution is trivial:
RFC 188 (v3) Objects : Private keys and methods
This and other RFCs are available on the web at http://dev.perl.org/rfc/ =head1 TITLE Objects : Private keys and methods =head1 VERSION Maintainer: Damian Conway <[EMAIL PROTECTED]> Date: 1 Sep 2000 Last Modified: 25 Sep 2000 Mailing List: [EMAIL PROTECTED] Number: 188 Version: 3 Status: Frozen =head1 ABSTRACT This RFC proposes two new keywords -- C and C -- that limit the accessibility of keys in a hash, and of methods. Their primary use would be to provide encapsulation of attributes and methods in hash-based objects. =head1 DESCRIPTION =head2 Private hash entries It is proposed that Perl 6 provide a unary function, C, that restricts hash entries to the current package. The keyword could be applied to a single hash entry: private $hash{key}; private $hash{$key}; private $hashref->{key}; or to a hash slice: private @hash{qw(_name _rank _snum)}; or to a complete hash (either directly, or via a reference): private %hash; private { _name => "demo", _rank => "private", _snum => 123 }; private bless { @attrs }, $class; bless private { @attrs }, $class; In all cases, a call to C would return its single argument. The effects of applying C to a single hash entry would be to: =over 4 =item 1. mark the entire hash as non-autovivifying (except via future calls to C or C -- see below) =item 2. mark the particular entry as being restricted to the package in which the call to C occurs =item 3. mark any other existing entries of the hash as publicly accessible (see L below). =back After a hash has been marked in this way, the specific key(s) would only be directly accessible in the same package: package MyClass; sub new { bless private { secret => 'data' }, $_[0] } package main; my $obj = MyClass->new(); print $obj->{secret}; # dies, inaccessible entry Attempts to autovivify keys of a C-ized hash would also be fatal: package MyClass; sub print_me { print $_[0]->{sekret} } # dies, no such entry package main; my $obj = MyClass->new(); print $obj->{public}; # dies, can't create entry Once a hash has been C-ized, the only way to extend its set of entries is via another call to C (or C -- see below): sub new { my ($class, %self) = @_; bless private \%self, $class; $self{seed} = rand; # dies, can't autovivify private $self{seed} = rand; # okay $self{seed} = rand; # now okay } Applying C to a hash slice would apply it individually to each entry in the slice. Applying C to an entire hash (directly, or via a reference) would apply it to every entry in the hash that is not already private (or public -- see below). =head3 C entries and inheritance Private entries of hashes could be I accessed in packages that inherit from the entry's package, by qualifying (i.e. prefixing) the key with the entry's package name. For example: package Base; sub new { my ($class, @data) = @_; bless private { data => [@data] }, $class; } package SortableBase; use base 'Base'; sub sorted { my ($self) = @_; print sort @{ $self->{Base::data} }; } Note, however, that it would still be a fatal error to attempt to access a private entry outside its package's hierarchy, even with full qualification: package main; my $obj = Base->new(@data); print $obj->{Base::data}; # dies, not in derived class Because private entries are only directly acccessible within their own package, a hash could be given two private entries with the same key, but associated with different packages. For example: package Base; sub new { my ($class, @data) = @_; bless private { data => [@data] }, $class; } sub data { return $_[0]->{data} }; # Base::data package Derived; use base 'Base'; sub new { my ($class, $derdatum, @basedata) = @_; my $self = $class->SUPER::new(@basedata); private $self->{data} = $derdatum; return $self; } sub data { return $_[0]->{data} }; # Derived::data Note that this solves the pernicious "data collision" problem in OO Perl. =head3 Iteration of C-ized hashes When a C-ized hash is iterated -- via C, C, or C -- the only keys or values returned would be those that are directly or indirectly accessible within the current package. Furthermore, iterators that return keys would alw
Pulling RFC 161
Unless I hear compelling arguments to the contrary, I'll be withdrawing RFC 161 on Tuesday due to lack of interest. Matt Youell [EMAIL PROTECTED]
Re: RFC 265 (v1) Interface polymorphism considered lovely
Nathan Wiger <[EMAIL PROTECTED]> writes: > > >package Doggie; > > > > > >sub isborn { > > >bless { @_ }, self; # ;-) > > >} > > >sub scratches ($\@;@) { > > >... > > >} > > > > > > > > >package Doggie::Cute; > > > > > >use base 'Doggie'; > > >use interface 'Pet'; > > > > > ># Our base class is 'Doggie', which does not use the 'Pet' > > ># interface (perhaps unbeknownst to us!). Nonetheless, we use > > ># the 'Pet' interface to make sure that our class is implemented > > ># correctly. > > > > > ># code would follow... > > > > This could still be C and it would work you know. > > No, it couldn't - notice that Doggie does not inherit from Pet. Unless > there's something about OO inheritance that I'm really missing... You can use C more than once you know? Or you can do: use base qw/Doggie Pet/; If we introduce the C syntax instead of just using C then the compiler will no that Doggie is a Class and Pet is an interface. Personally I think there's room for confusion there and I'd rather don belt *and* braces, but that doesn't mean we *can't* give people enough rope. > > reasoning behind seperating C and C (for me) > > is simply because of the mnemonic assistance to the programmer. > > interface.pm could easily be a duplicate of base.pm with the added > > restriction that that the package so included *must* be an interface. > > Yes, and I think that's a very worthwhile distinction. It also allows > you to mandate that you use multiple interfaces and a different base to > boot. This is a stretch but you should get the idea: > >package Solaris::Devices::Ethernet::GigEther; > >use base 'Solaris::Devices::Ethernet'; > >use interface 'Solaris::Kernel::Kmem'; >use interface 'Solaris::Devices::Devtree'; > > But maybe I'm barkings up a different tree from you. Hard to tell. You seem to be assuming that I know rather more about the way Solaris handles devices than I actually do, which makes it kind of hard to know what you're tilting at here. > But it seems that interfaces don't have to be constrained to just > stub base class definitions. Instead, they can serve as > specifications for class interaction as well as class > implementation. Er... if you mean what I think you mean then that's kind of the point. > If we keep "use interface" and "use base" separate then this becomes > trivial to do (compile-time checks for proper method > declarations/etc). Damian's point was that, if we introduce an C keyword rather than overloading C then the C pragmatic module can work all that out by looking at whether an identifier was declared as a package or as an interface. And he's right, technically. But there's a 'social' implication we need to take into account. I think I've just started to repeat myself... -- Piers