Larry Wall wrote:
> > Users of the class includes people subclassing the class, so to them
> > they need to be able to use $.month_0 and $.month, even though there
> > is no "has $.month_0" declared in the Class implementation, only
> > "has $.month".
We thought about defining the attribute variables that way,
but decided that it would be clearer if they only ever refer to
real attributes declared in the current class.

Clearer in what way?

This implies that you cannot;

  - refactor classes into class heirarchies without performing
    code review of all methods in the class and included roles.

  - "wrap" internal attribute access of a superclass in a subclass

This in turn implies that the $.foo syntax is, in general, bad
practice!

Allow me to demonstrate with an example, taken from S12 with
additions:

    role Pet {
        has $.collar = { Collar.new(Tag.new) };
        method id () { return $.collar.tag }
        method lose_collar () { undef $.collar }
        has $.owner;
    }

    class Dog does Pet {
        has $.location;
        has $.home;
        does Run;
        method play {
            if $owner.location ~~ $.location {
                 $?SELF.lose_collar();
            } else {
                 $?SELF.run();
            }
        }
    }

Now, as a user of the "Dog" class, I want to specialise it so that
the collar cannot be removed unless the dog is at home;

    class Rotweiler is Dog {
        method collar {
            Proxy.new(
                STORE => sub($self, $val) {
                    if ($val or $.location ~~ $.home) {
                        $self.SUPER::collar = $val;
                    } else {
                        die "rotweilers must be kept on a leash"
                    }
                },
                FETCH => { $self.SUPER::collar },
            );
        }
    }

OK, so that's all well and good - you've changed the public property
"collar" so that your extra logic is there.

But what happens?  You lend your dog to someone else, they call
$dog.play, which calls lose_collar(), which sets $.collar directly.
Whoops, your Rotweiler is on the loose and slobbering over some
unsuspecting 4 year old.

This means that people designing classes and roles have to conciously
make the decision to use $?SELF.foo or ./foo() instead of the more
tempting looking and consistent $.foo

Perhaps you could elucidate your point by giving some examples of
when you *wouldn't* want $.foo to mean ./foo(), and when using a
private attribute would not be the "correct" solution.

: These simple definitions should make all sorts of OO tricks possible,
: and reduces the definition of Classes to one that is purely
: functional (ie, state is just a set of functions too).
One can certainly rewrite $.foo and $:foo in terms of lower level
functional primitives, but we must be careful not to confuse those
with higher-level virtual method calls.  Otherwise we are mixing OO
interface with OO implementation, and we've already discovered in
Perl 5 that that's a Bad Idea.

Funnily enough, I found in Perl 5 that it's a good idea.  Perhaps I
should demonstrate;

  package MyObject;
  use base qw( Class::Tangram );

  # define a string accessor for attribute "foo"
  our $fields = { string => ["foo"] };

  sub get_foo {
      my $self = shift;
      return $self->SUPER::get_foo . "bar";
  }
  sub set_foo {
      my $self = shift;
      my $new_foo = shift;
      return $self->SUPER::set_foo($new_foo . "baz");
  }

  package main;
  my $object = MyObject->new(foo => "foo");

  print $object->foo, "\n";   # prints "foobazbar"

As you can see, instead of ever looking into the object's internal
state, the "superclass" accessor is always used to find the object's
internal state.  This happens by munging @ISA at 'schema import'
time, and building the accessors in an extra inserted class.  Never
do you have to use $object->{foo}; in a sense, so long as you don't
circumvent the designed interface, the objects are already "opaque".

Interfaces between organisms are
cleaner when their innards stay in and their outtards stay out.

Cleaner, perhaps - but how will they ever reproduce?

Seriously, this isn't about innards (private attributes/properties)
and outtards (public attributes/properties).  This is about if you
make a new version and replace one of the outtards, that the
replaced outtards are not used anyway.

Perhaps it would be better to stick to mechanical things.  As you
have already stated you do not want to include general Quantum
Mechanical theory of extended entanglement into Perl 6 [1], it is
unlikely that we will be designing organisms with it.  Organisms do
not fit the mould; they do not reduce easily into clean components,
each piece of the whole is connected to the other via a quantum
entanglement field.  It is therefore not object oriented as the
internal state of every part of the system affects the whole.

So, I will use the analogy of an Automobile.  If you replace the
Engine of the automobile, you wouldn't want to have to replace the
accelerator because it worked on the old $.engine.  You just make
sure all the engine responds correctly to the messages passed to
it via the formal defined interface and go for a ride.

Sam.

1. http://xrl.us/gsmd

Reply via email to