Re: RFC 95 (v2) Object Classes
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
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
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
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
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,