Re: RFC 95 (v2) Object Classes

2000-08-22 Thread Nick Ing-Simmons

Hildo Biersma <[EMAIL PROTECTED]> writes:
>
>> =head2 Inheritance
>> 
>> As with the existing C/C pragmata, Perl 6
>> classes should support single, linear inheritance only.  Multiple
>> inheritance is generally more trouble than it's worth.
>
>Yuck.  MI is useful though sometimes abused, and even (cough) Java
>supports multiple inheritance of interfaces.  There is existing perl5
>code using mulitple inheritance that we should be able to support in
>perl 6.

Multiple inheritance is useful for 'mixins'. For example Tk has a 
'mixin' class Tk::Wm which is used as a prefix to the @ISA list 
of widgets which are "toplevels" and thus should respond to methods 
relating to the "Window Manager".

These "mixin" classes typically add extra methods which are defined in terms
of methods of the "core" object. As such they do not _usually_ require 
attribute space in the object.

-- 
Nick Ing-Simmons




Re: RFC 95 (v2) Object Classes

2000-08-18 Thread Hildo Biersma

I disagree with this in so many places that I don't really know where to
start...

First, I do agree with the view perl should have better support for
classes.  Also, should the author want to, protection features from C++
(or other B&D languages) should be supported optionally.

> NOTE: these and other examples assume Highlander Variables (RFC 9)
> where '$mage', '@mage' and '%mage' all refer to different "views" of
> the same variable, rather than different variables as in Perl 5.
> Otherwise read '@mage' as '@$mage' and '%mage' as '%$mage'.

The implementation of a class should be invisible to the outside, so
details like this should not matter.

> 
> When it comes to creating objects, a hash is the most common choice of
> structure for blessing as it offers the most versatility.  However,
> you can get faster access and use less memory by using a list.  The
> downside is that you lose the ability to reference items by name.
> A pseudo-hash provides the efficency of a list with the convenience of
> hash.

Why not take this a step further?  Let's propose that, once you define a
class, perl will use some efficient implementation that allows named
access to the class and object data members.  All other access (as
array, hash, whatever) is forbidden, allowing perl to take whatever
internal implementation it sees fit.

>> =head2 Defining a class
> 
> The new C keyword is proposed for defining an object class.
> This can be thought of as a special kind of C.  Lexical
> variables defined within the scope of a class declaration become
> attributes (or data members) of that class.  The existing C
> keyword indicates per-instance variables while C is used to
> create class variables which are shared across all instances of a
> given class
> 
> class Person;
> our $home  = 'Middle Earth';# class variable
> my ($name, $race, @aliases);# object (instance) variables
> 
> The class definition would continue until the next C or
> C declaration, or until the end of the current file.
> Class definitions can be re-opened and extended.

Oh dear.  Re-opening a class leads to trouble - not just for editors,
debuggers and class browsers, but also for the compiler, which can
generate code right from the point the class definition closes.  Why not
allow forward class declarations and require all of a class to be
defined at one point?  What feature requiers re-opening a class?


> =head2 Accessing variables and methods
> 
> Object variables are accessed using the familiar C<-E> operator.
> 
> print $mage->name, " has ",
>   scalar @mage->aliases, " aliases\n";

Object variables should never be visible to the outside world unless
accessor functions have been declared.  Even then, objects that define
accessors for all object variables are typically indicative of poor
design. The only access to object variables should be within the class
and, for designated member variables, to derived classes.

> =head2 Inheritance
> 
> As with the existing C/C pragmata, Perl 6
> classes should support single, linear inheritance only.  Multiple
> inheritance is generally more trouble than it's worth.

Yuck.  MI is useful though sometimes abused, and even (cough) Java
supports multiple inheritance of interfaces.  There is existing perl5
code using mulitple inheritance that we should be able to support in
perl 6.
 
> =head2 Constructor Methods
> 
> The default class constructor method, new(), should be available if
> otherwise undefined in the class.  It should instantiate an empty
> object (via C), assign any parameters to object
> variables and then call any per-object initialisation method, NEW()
> (or _new()?).  Base class NEW() constructors should be called in
> order.  Note that the C<$class> variable should be correctly defined
> in the base class (e.g. Person) to contain the name of the derived
> class (User).

This is undesirable policy that should not be imposed on the coder.  In
my persistent object package, objects are created using Build() or
Restore().  If I don't want to give the users a new() method, I should
be able to do so - without having to create a 'this is not a new'
method.  This also comes up when defining Factory or Singleton classes.

Hildo



Re: RFC 95 (v2) Object Classes

2000-08-18 Thread David L. Nicol

John Siracusa wrote:

> Object attributes should be accessed through accessors that look and behave
> like accessors:
> 
> $name = $mage->name;


and Object qualifiers should be accessed through accessors that look like
qualifiers:

$mage : (HASHTYPE = 'packed_static')

 
> I'd like to see a *distinct syntax and implementation* for objects. (The
> following example is just off the top of my head and is not meant to be a
> syntax recommendation, but the spirit is there.)


I don't mind if they behave like key-value pairs, as long as they are
really packed structures internally.  I want to load in raw C++ headers
with C and have all structures and classes become defined in the
current package. (RFC 61 version 2)  

Thing.OUTER.inner.which 

will become 

$$$Thing{OUTER}{inner}{which}

but that is all right as the compiler will still turn that into an access to
the seventh and eighth bits in the 57th byte from the beginning of the structure
and print it out in STRING context as 'RED' 'GREEN' or 'BLUE' which are the
enumerated types associated with that field.



> Classes should be called classes, not packages.  We could even keep packages
> and the whole Perl 5 o-o implementation around.  It won't interfere with
> Perl 6 o-o because Perl 6 o-o does not dress up and overload normal data
> structures to make "objects."  So yes, it should be:
> 
> class Person;
> 
> Same deal with methods.  Subroutines are subroutines and methods are
> methods.


>  Let's say we want to do more than set/get the name attribute via a
> single scalar:
> 
> method name
> {
>   my($first, $last) = @_;
> 
>   $self.name = $first . ' ' . $last;
> }
> 
> Here we see an implicit $self (available in all methods), normal arg
> handling via @_ (with the 0th arg no longer being a ref to self), a new
> syntax for accessing attributes inside custom methods of the same name
> ($self.name), and an implicit return of the name attribute (did I mention
> that get/set should return the current/new value of an attribute?)

cool, very cool.



Re: RFC 95 (v2) Object Classes

2000-08-17 Thread John Siracusa

On 8/17/00 5:36 PM, Perl6 RFC Librarian wrote:
> NOTE: these and other examples assume Highlander Variables (RFC 9)
> where '$mage', '@mage' and '%mage' all refer to different "views" of
> the same variable, rather than different variables as in Perl 5.
> Otherwise read '@mage' as '@$mage' and '%mage' as '%$mage'.

I don't agree with the premise that objects should look and behave like
traditional Perl data structures.  Objects are objects, not arrays or
hashes.  The farthest I'd go is using scalars to hold references to objects.

$mage = Person->new(...);

Object attributes should be accessed through accessors that look and behave
like accessors:

$name = $mage->name;

The default behavior for attributes should be get/set, not just get.  I
never, ever want to have to write a method like this:

> sub name {# specific accessor method
>   if (@_) {
>   $name = shift;
>print "changed name to $name\n"
>  if $debug;
>   }
>   return $name;
> }

Get/set should be the default, stupendously efficient behavior:

$mage->name('Merlin'); # Be fast!

print $mage->name; # Be fast!

An attribute should be able to hold any valid Perl value:

$mage->friends([ 'Gandalf', 'Oz' ]);
$mage->warts({ big => 5, small => 2 });

possibly including collections:

$mage->spells('fire', 'wind', 'ice');

print 'Summon the ', ($mage->spells)[1];

$mage->robes(big => 7, small => 2);

Again, this is the default, no-need-to-roll-your-own, wickedly fast native
object attribute access interface.

As for interpolation into strings:

print "$mage->name commands you!";

I can take it or leave it.  It seems like it might muck things unless you
also allow user-defined methods to interpolate as well.
   
This type of attribute assignment:

> $Person->debug = 1;# activate debugging

also alienates user-defined methods unless you're willing to go puck
nutty with lvalue subs (which give me the willies).

> # EITHER
> my $mage = Person->new(  # use positional parameters
> "Gandalf", 
> "Istar", 
> ["Mithrandir", "Olorin", "Incanus"]
> );

Positional parameter construction support is fine, but this is better:

> # OR
> my $mage = Person->new(  # use named parameters
> name=> "Gandalf",
> race=> "Istar",
> aliases => ["Mithrandir", "Olorin", "Incanus"]
> );

Like I said, I think this is evil:

> print " aka: @mage->aliases\n"; # ditto

If "aliases" contains an array:

$mage->aliases('Fred', 'Joe');

then it should work like this:

print $mage->aliases;   # "FredJoe"

# If you allow interpolation:
print "$mage->aliases;" # "Fred Joe"

More evil:

> # use it like a list
> my ($name, $race, $aliases) = @mage;

Ick, please no.  First of all, if you want an array, use an array. Second, I
never want to have to know the order of an object's attributes!  Talk about
fragile.
 
> # use it like a hash, with keys returned in correct order
> my @keys = keys %mage;# 'name', 'race', 'aliases'

Ditto.  Bleh.

I'd like to see a *distinct syntax and implementation* for objects. (The
following example is just off the top of my head and is not meant to be a
syntax recommendation, but the spirit is there.)

Classes should be called classes, not packages.  We could even keep packages
and the whole Perl 5 o-o implementation around.  It won't interfere with
Perl 6 o-o because Perl 6 o-o does not dress up and overload normal data
structures to make "objects."  So yes, it should be:

class Person;

Same deal with methods.  Subroutines are subroutines and methods are
methods.  Let's say we want to do more than set/get the name attribute via a
single scalar:

method name
{
  my($first, $last) = @_;

  $self.name = $first . ' ' . $last;
}

Here we see an implicit $self (available in all methods), normal arg
handling via @_ (with the 0th arg no longer being a ref to self), a new
syntax for accessing attributes inside custom methods of the same name
($self.name), and an implicit return of the name attribute (did I mention
that get/set should return the current/new value of an attribute?)

All of the syntax and rules in this example are arbitrary, however.  The
take-home point here is that *this is a METHOD*, not a fancy subroutine.

The same goes for classes themselves, which should be "class objects" that
instantiate objects by cloning a prototype or what have you, so we can stop
slinging around "Strings::Like::This"

Summary: Perl 6's o-o syntax and implementation should not be constrained by
Perl 6's procedural interface, nor should it be shoehorned into overloaded
versions of Perl data structures.

-John




RFC 95 (v2) Object Classes

2000-08-17 Thread Perl6 RFC Librarian

This and other RFCs are available on the web at
  http://dev.perl.org/rfc/

=head1 TITLE

Object Classes

=head1 VERSION

Maintainer: Andy Wardley <[EMAIL PROTECTED]>
Date: 11 Aug 2000
Last Modified: 17 Aug 2000
Version: 2
Mailing List: [EMAIL PROTECTED]
Number: 95

=head1 ABSTRACT

This RFC proposes a syntax and semantics for defining object classes
in Perl 6.  It introduces the C keyword, which can be thought
of as a special kind of C which incorates the functionality
of the Class::Struct module while giving the compile time typo
checking and access optimisation of the C pragma.  This
object class is an extension of the C mechanism, not a
replacement for it.

=head1 SYNOPSIS

NOTE: these and other examples assume Highlander Variables (RFC 9)
where '$mage', '@mage' and '%mage' all refer to different "views" of
the same variable, rather than different variables as in Perl 5.
Otherwise read '@mage' as '@$mage' and '%mage' as '%$mage'.

class Person;
our $debug = 0; # class variable
my ($name, $race, @aliases);# object (instance) variables

sub name {  # specific accessor method
if (@_) {
$name = shift;
print "changed name to $name\n"
if $debug;
}
return $name;
}

package main;
$Person->debug = 1; # activate debugging

# EITHER
my $mage = Person->new(  # use positional parameters
"Gandalf", 
"Istar", 
["Mithrandir", "Olorin", "Incanus"]
);

# OR
my $mage = Person->new(  # use named parameters
name=> "Gandalf", 
race=> "Istar", 
aliases => ["Mithrandir", "Olorin", "Incanus"]
);

# access via named attributes
print "name: $mage->name\n";# calls name() method
print "race: $mage->race\n";# optimised to direct access
print " aka: @mage->aliases\n"; # ditto

# use it like a list
my ($name, $race, $aliases) = @mage;

# use it like a hash, with keys returned in correct order
my @keys = keys %mage;  # 'name', 'race', 'aliases'

=head1 OVERVIEW

When it comes to creating objects, a hash is the most common choice of
structure for blessing as it offers the most versatility.  However,
you can get faster access and use less memory by using a list.  The
downside is that you lose the ability to reference items by name.  
A pseudo-hash provides the efficency of a list with the convenience of
hash.

my $ph = [ { one => 1, two => 2 }, 'foo', 'bar' ];
print $ph->{one};   # 'foo'
print $ph->[2]; # 'bar'

It works just like a hash but be warned that you can't treat it like a
regular list without taking into account the an extra item, the hash
array reference, at the start of the list.

@$ph = ('wiz', 'waz');  # wrong!

The C pragma relies on pseudo-hash magic to make it
possible to access array elements by name.  Furthermore, the compiler
is smart enough to optimise access to the fields into straight array
accesses.  It also validates field names for typo safety.  These are
both Good Things.  That's all it does, though.  You still have to
build your own object constructor which calls the fields::new()
method.

package Person;
use fields qw( name race aliases );

sub new { 
my $type = shift;
my Person $self = fields::new(ref $type || $type);
...
return $self;
}

package main;
my $mage = Person->new();
$mage->{name} = "Gandalf";

You can provide accessor methods as wrappers around the fields, but
note that you then have to change your code to call the methods instead
of accessing the hash fields directly.

package Person;
...
sub name{ ... }
sub race{ ... }
sub aliases { ... }

package main;
my $mage = Person->new();
$mage->name("Gandalf"); # changed from '$mage->{name}'

The Class::Struct method goes one step better but also takes two steps
back.  On the plus side, it automatically builds a default constructor
method and accessor methods for your class.  On the negative side, you
gain an extra level of indirection to each item, losing the compile
time optimisation and typo checking.  Furthermore, you have to specify
your class using an unusual syntax to keep the parser happy.

package Person;
use Class::Struct;
struct Person => {
name=> '$', # not as obvious as '$name'
race=> '$', # etc...
aliases => '@',
};

One nice thing about the Class::Struct approach is that you can provide
your own package subroutines which override the defaults.  Unfortunately
you're also paying the price of method calls every time you access an
attribute whether you've defined a custom accessor method or not.

The C keyword is proposed as a way to implement the 
functionality of Class::Struct, with the compile time benefits
of the C pragma,