RFC 101 (v3) Apache-like Event and Dispatch Handlers

2000-09-25 Thread Perl6 RFC Librarian

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

2000-09-25 Thread Perl6 RFC Librarian

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

2000-09-25 Thread Nathan Wiger

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

2000-09-25 Thread Nathan Wiger

> 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

2000-09-25 Thread Damian Conway

RFC 189 covers this.

Damian



RFC 307 (v1) PRAYER - what gets said when you C something

2000-09-25 Thread Perl6 RFC Librarian

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

2000-09-25 Thread Perl6 RFC Librarian

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

2000-09-25 Thread Perl6 RFC Librarian

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 Thread Bennett Todd

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

2000-09-25 Thread Perl6 RFC Librarian

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

2000-09-25 Thread Perl6 RFC Librarian

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

2000-09-25 Thread Perl6 RFC Librarian

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

2000-09-25 Thread Matt Youell

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

2000-09-25 Thread Piers Cawley

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