Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Interfaces

3 views
Skip to first unread message

Michael G Schwern

unread,
Sep 29, 2002, 8:11:37 PM9/29/02
to perl6-l...@perl.org
Recently I presented a Perl 6 overview talk at a Java conference. The
audience was mostly mute, which is unfortunate as I wanted to hear some
feedback or at least some groans of pain, but there was one Lisp programmer
in the front row that asked some interesting questions.

One was "Perl 6 support interfaces?" meaning Java style interfaces.
Figuring that we now have proper subroutine prototypes and assuming forward
declarations stayed in the language, sure we'd effectively have interfaces.
Thinking on it afterwards, there's a bit more to it that that.

If I was to declare an abstract class using "interfaces" in Perl 6, I'd
figure it would look something like this:

class Toilet;

method flush_capacity ($liters);
method plunge ();
method flush ();
method fill ($liters);
method water_height ();
method seat_up ();
method seat_down ();

and then all you have to do is subclass and implement those methods. In
order for this to really be interfaces, there would have to be a few more
things.

- Overriding methods would have to have the same signature as the parent.
If not, a warning or error would be issued.

class Crapper isa Toilet;

# Ok. Variable name different, signature the same.
method flush_capacity ($litres) {
...
}

# Ok, but illustrates that signatures will have to have types
# to really be useful.
method fill ($gallons) {
...
}

# Not ok. Wrong signature.
method plunge ($plunger) {
...
}

# Ok? The old signature will still work, we've just added
# an extra, optional argument. [1]
method water_height (;$metric_or_imperial) {
...
}

- Methods left unimplemented should issue a warning or error at compile-time.
Anything left for autoloading should probably be declared as such.

class Loo isa Toilet;

method water_height () is autoloaded;


Here's some open problems:

Would this be the default behavior for overridden methods, or will the
parent class/methods have to be declared "is interface" for the signatures
to be enforced on subclasses?

Will interfaces be ignorable?

What if a subclass adds extra, optional arguments to a method, is that ok?

What about the return type? If you're doing strict OO it would be nice to
specify the signature of the return value as well, which will get
interesting to be able to describe totally the various ways in which a
method can return in different contexts.


[1] I don't know what Perl 6 signatures will use for optional arguments,
so I'll just use the Perl 5 style.

--

Michael G. Schwern <sch...@pobox.com> http://www.pobox.com/~schwern/
Perl Quality Assurance <per...@perl.org> Kwalitee Is Job One
Do you have a map? Because I keep getting lost in your armpits.

Michael Lazzaro

unread,
Sep 30, 2002, 1:12:48 PM9/30/02
to Michael G Schwern, perl6-l...@perl.org

On Sunday, September 29, 2002, at 05:11 PM, Michael G Schwern wrote:
> Here's some open problems:
>
> Would this be the default behavior for overridden methods, or will the
> parent class/methods have to be declared "is interface" for the
> signatures
> to be enforced on subclasses?

Heck, I'll jump into this one, since I've been working in _way_ too
many OO variations lately, some of them inflicted upon myself. While I
hope perl6 will allow extendable OO methodologies, the out-of-box one
needs to be as robust as possible. Here's a strawman opinion we can
argue against:

I originally thought I was going to argue that it should be the default
behavior (to avoid yet more cruft in the method prototype) but thinking
about it more, I'll make the case that yes, you should have to say "is
interface", if that's what you mean.

The reason being "private" methods; while the interfaces to an object
must remain consistent, I don't think we should enforce the same rigor
on internal methods of a class. There are cases where you want
something like:

method do_internal_initialization ($num) { ... }

but you don't care if you stomp on it's name for certain subclasses
that need similar private methods:

method do_internal_initialization ($hashref) { ... }

(...leading to an additional question, will there be a way to specify
methods of a class that are *not* inherited by subclasses?) So I'd say
we either need "is interface", or (worse) "is not interface".

> Will interfaces be ignorable?

.... and if we _do_ say any of the above, then they are not ignorable,
on pain o' death. I'd argue there shouldn't be any way around it,
period, or we lose the whole point of the implied consistency. Can
anyone think of a counterexample?

> What if a subclass adds extra, optional arguments to a method, is that
> ok?

This is the scariest question, I think... In theory, yes, there are
lots of potential interfaces that would benefit from optional
extensions, & I've made a few. In strict terms, though, they violate
the whole idea of "common, invariant interface", so I never know if
what I've done is Acceptable, or a Shameful Hack... anyone care to
make a case either way on this one?

> What about the return type? If you're doing strict OO it would be
> nice to
> specify the signature of the return value as well, which will get
> interesting to be able to describe totally the various ways in which a
> method can return in different contexts.

While I cannot conceive what monstrosity of syntax we could put in the
method prototype to say "I want to return this type in this context,
and this type in this context, etc., etc.", I would argue that
specifying it is an absolute necessity; a fundamental part of an
Interface is the type of information it returns: we have to define it
as part of the Interface (including all recognized contexts), or we set
ourselves up such that different subclasses may return their
information differently. Better to enforce it? (Of course, if our
interface "a" is returning an object, of a class that flattens itself
differently in different contexts, then do we say the interface can
only return object classes derived from that first object class? And
do we restrict the possible "flattenings" of the object class itself,
using an interface, so subclasses of the returned obj can't muck with
it and unintentionally violate our first interface ("a")?... there's a
can of worms, boy...)

Mike Lazzaro
Cognitivity (http://www.cognitivity.com/)

Michael G Schwern

unread,
Sep 30, 2002, 8:23:15 PM9/30/02
to Michael Lazzaro, perl6-l...@perl.org
On Mon, Sep 30, 2002 at 10:12:48AM -0700, Michael Lazzaro wrote:
> Heck, I'll jump into this one, since I've been working in _way_ too
> many OO variations lately, some of them inflicted upon myself. While I
> hope perl6 will allow extendable OO methodologies, the out-of-box one
> needs to be as robust as possible. Here's a strawman opinion we can
> argue against:
>
> I originally thought I was going to argue that it should be the default
> behavior (to avoid yet more cruft in the method prototype) but thinking
> about it more, I'll make the case that yes, you should have to say "is
> interface", if that's what you mean.
>
> The reason being "private" methods; while the interfaces to an object
> must remain consistent, I don't think we should enforce the same rigor
> on internal methods of a class.

Internal methods would simply be declared private and not be inherited, so
its not a problem.

method _do_internal_init ($num) is private {
...
}

Last I heard, Perl 6 will have basic privacy enforcement, something like the
above.


> >Will interfaces be ignorable?


>
> ... and if we _do_ say any of the above, then they are not ignorable,
> on pain o' death. I'd argue there shouldn't be any way around it,
> period, or we lose the whole point of the implied consistency. Can
> anyone think of a counterexample?

If I inherit from some parent which is well designed except for one really
poorly designed method.

Or maybe the parent class uses a really good name for a really silly
purpose, and I want that name back.

Or maybe I do want to deliberately have a subclass which is different than
the parent.

Or maybe the parent accidentally inherits something, perhaps via multiple
inheritence, and now I'm suck with it.

Not all subclasses are simply functional extensions of the parent. In these
cases I should have a way to get around the interface restriction, probably
as an attribute to the overriding method.

OTOH, Java interfaces have a loophole which is considered a design mistake.
An interface can declare some parts of the interface optional and then
implementors can decide if they want to implement it or not. The upshot
being that if you use a subclass in Java you can't rely on the optional
parts being there.

This comes down to an OO philosophy issue. If Perl 6 wants a strict OO
style, don't put in a loophole. If they want to leave some room to play,
put in the ability to turn some of the strictness off.


> >What if a subclass adds extra, optional arguments to a method, is that
> >ok?
>
> This is the scariest question, I think... In theory, yes, there are
> lots of potential interfaces that would benefit from optional
> extensions, & I've made a few. In strict terms, though, they violate
> the whole idea of "common, invariant interface", so I never know if
> what I've done is Acceptable, or a Shameful Hack... anyone care to
> make a case either way on this one?

The child's interface still supports the complete interface of the parent,
so I don't see it as a problem. Sure beats having to write a whole new set
of method names just because you want to add an extra argument on the end.


> >What about the return type? If you're doing strict OO it would be
> >nice to
> >specify the signature of the return value as well, which will get
> >interesting to be able to describe totally the various ways in which a
> >method can return in different contexts.
>
> While I cannot conceive what monstrosity of syntax we could put in the
> method prototype to say "I want to return this type in this context,
> and this type in this context, etc., etc."

To paraphrase Damian at YAPC::Europe, "It's Damian's problem." ;)

> Better to enforce it? (Of course, if our
> interface "a" is returning an object, of a class that flattens itself
> differently in different contexts, then do we say the interface can
> only return object classes derived from that first object class?

Yes. The object class is simply a return type.


> And do we restrict the possible "flattenings" of the object class itself,
> using an interface, so subclasses of the returned obj can't muck with
> it and unintentionally violate our first interface ("a")?... there's a
> can of worms, boy...)

At that point you want to use the Design By Contract features, probably via
a class invariant, to ensure that all your subclasses flatten the same way.


--

Michael G. Schwern <sch...@pobox.com> http://www.pobox.com/~schwern/
Perl Quality Assurance <per...@perl.org> Kwalitee Is Job One

"In my day, we didn't have none of yer new-fangled token-pasting
operators! We stuck the tokens together with our BARE HANDS and we
LIKED IT."
-- Mark-Jason Dominus fondly remembers perl 1.0
in <2002030412132...@plover.com>

Simon Cozens

unread,
Sep 30, 2002, 8:36:19 PM9/30/02
to perl6-l...@perl.org
sch...@pobox.com (Michael G Schwern) writes:
> method _do_internal_init ($num) is private {

Just thinking aloud, would
sub foo is method is private is integer is fungible {

be better written as
sub foo is fungible private integer method {

or not?

--
Those who do not understand Unix are condemned to reinvent it, poorly.
- Henry Spencer, University of Toronto Unix hack

David Whipp

unread,
Sep 30, 2002, 9:04:28 PM9/30/02
to Michael Lazzaro, Michael G Schwern, perl6-l...@perl.org
Michael Lazzaro wrote:
> > What if a subclass adds extra, optional arguments to a
> > method, is that ok?
>
> This is the scariest question, I think... In theory, yes, there are
> lots of potential interfaces that would benefit from optional
> extensions, & I've made a few. In strict terms, though, they violate
> the whole idea of "common, invariant interface", so I never know if
> what I've done is Acceptable, or a Shameful Hack... anyone care to
> make a case either way on this one?

I don't think that the addition of an optional parameter
violates any substitution principle: users of the base-class
interface couldn't use the extra params (because they're not in
the interface); but a user of the derived-class's interface
can use the extra power (because they are in that interface).
A derived class is always allowed to add things (thus, you can
weaken preconditions, stengthen postconditions, add extra
methods, return a more specific result, ...; but you can't
strengthen a precondtion, nor weaken a postcondition, etc.)


On a slightly different note, if we have interfaces then I'd really
like to follow the Eiffel model: features such as renaming methods
in the derived class may seem a bit strange; but they can be useful
if you have have name-conflicts with multiple inheritance. Oh yes,
and we need to make sure DBC stuff is part of the interface, not
the implementation.


Dave.

Michael G Schwern

unread,
Sep 30, 2002, 11:16:20 PM9/30/02
to Simon Cozens, perl6-l...@perl.org
On Tue, Oct 01, 2002 at 01:36:19AM +0100, Simon Cozens wrote:
> sch...@pobox.com (Michael G Schwern) writes:
> > method _do_internal_init ($num) is private {
>
> Just thinking aloud, would
> sub foo is method is private is integer is fungible {
>
> be better written as
> sub foo is fungible private integer method {
>
> or not?

How about seperated by commas, like any other list?

method foo is fungible, private, integer {


--

Michael G. Schwern <sch...@pobox.com> http://www.pobox.com/~schwern/
Perl Quality Assurance <per...@perl.org> Kwalitee Is Job One

"That's what Jagulars always do," said Pooh, much interested. "They call
'Help! Help!' and then when you look up they drop down on you."

Frank Wojcik

unread,
Sep 30, 2002, 11:22:18 PM9/30/02
to perl6-l...@perl.org
On Mon, Sep 30, 2002 at 11:16:20PM -0400, Michael G Schwern wrote:
> How about seperated by commas, like any other list?
>
> method foo is fungible, private, integer {

Well, if we're going to use a /list/, how about

method foo ($param) ^is (fungible, private, integer) {

?

:) 1/2

Michael G Schwern

unread,
Sep 30, 2002, 11:19:44 PM9/30/02
to David Whipp, Michael Lazzaro, perl6-l...@perl.org
On Mon, Sep 30, 2002 at 06:04:28PM -0700, David Whipp wrote:
> On a slightly different note, if we have interfaces then I'd really
> like to follow the Eiffel model: features such as renaming methods
> in the derived class may seem a bit strange; but they can be useful
> if you have have name-conflicts with multiple inheritance.

I'm not familiar with the Eiffel beyond "it's the DBC language and it's
French", but wouldn't this simply be covered by aliasing?

Which I guess raises the question, is a method's signature and attributes
part of the method itself, or it's name? In other words, do aliases to the
same method carry the same signature and attributes?


> Oh yes, and we need to make sure DBC stuff is part of the interface, not
> the implementation.

Sensible.


--

Michael G. Schwern <sch...@pobox.com> http://www.pobox.com/~schwern/
Perl Quality Assurance <per...@perl.org> Kwalitee Is Job One

Playstation? Of course Perl runs on Playstation.
-- Jarkko Hietaniemi

Michael Lazzaro

unread,
Oct 1, 2002, 2:51:02 PM10/1/02
to perl6-l...@perl.org

On Monday, September 30, 2002, at 05:23 PM, Michael G Schwern wrote:

> OTOH, Java interfaces have a loophole which is considered a design
> mistake.
> An interface can declare some parts of the interface optional and then
> implementors can decide if they want to implement it or not. The
> upshot
> being that if you use a subclass in Java you can't rely on the optional
> parts being there.
>
> This comes down to an OO philosophy issue. If Perl 6 wants a strict OO
> style, don't put in a loophole. If they want to leave some room to
> play,
> put in the ability to turn some of the strictness off.

I guess what bothers me is the loophole issue, sort of... in specific,
who gets to decide whether a given interface method is optional. I'm
hoping that the optional-ness of an interface is itself optional. And
that the optional-ness of a non-optional interface is not optional. :-)

The problems arise anywhere you're referring to interface methods from
outside the class. It may be perfectly OK for a subclass of a given
class to reuse an interface method for a different purpose, etc., so
long as nothing outside the inheritance chain is using it... but I'd
very much like a way for an interface to say "don't muck with me", so
that sensitive interfaces can be guaranteed as forever invariant, if
you really, really mean it.

My hope is that you could define the "non-overridability" of a given
interface method in the parent class, to guarantee enforcement among
subclasses. Possible pseudocode choices include:

# (1) explicitly not an interface method
method foo (...) is private { ... }

# (2) explicitly an interface method
method foo (...) is interface { ... }

# (3) explicitly a "strict" interface, can't change it in subclasses
method foo (...) is strict interface { ... }

# (4) explicitly "optional", subclasses can muck with it
method foo (...) is optional interface { ... }

# (5) So what's the unattributed case? An implied interface,
# implied optional interface, or just explicitly not private?
method foo (...) { ... }

I'd say if we had (1), and if (2) enforced "strict", then (5) could
mean "optional, not private, but not strictly an interface either...",
and we wouldn't need the icky (3) or (4) at all. That would go nicely
with expectations, I think. (But are there other possibilities besides
"private" and "interface", e.g. "protected", etc.?)

On Monday, September 30, 2002, at 06:04 PM, David Whipp wrote:
>>> What if a subclass adds extra, optional arguments to a
>>> method, is that ok?
>>

>> ... In theory, yes...


>
> I don't think that the addition of an optional parameter
> violates any substitution principle: users of the base-class
> interface couldn't use the extra params (because they're not in
> the interface); but a user of the derived-class's interface
> can use the extra power (because they are in that interface).
> A derived class is always allowed to add things (thus, you can
> weaken preconditions, stengthen postconditions, add extra
> methods, return a more specific result, ...; but you can't
> strengthen a precondtion, nor weaken a postcondition, etc.)

Agreed. If we had some concept like "strict" vs. "overridable"
interfaces, should "strict" prevent this, too, or are extra, optional
parameters always allowed as a special case (under the assumption that
they can't hurt anything that doesn't know about them?)


>> if our interface "a" is returning an object, of a class that flattens
>> itself
>> differently in different contexts, then do we say the interface can
>> only return object classes derived from that first object class?

>> And do we restrict the possible "flattenings" of the object class
>> itself,
>> using an interface, so subclasses of the returned obj can't muck with
>> it and unintentionally violate our first interface ("a")?...

My musing is that the behavior of a class in different contexts is
itself an interface, in the sense of being a contract between a
class/subclass and it's users, and therefore could be expressible in
the same syntax as other interfaces, with the same issues of
(non)strictness. (And for that matter, the contextual return values of
any arbitrary function, foo(), can be expressed as an interface to a
one-off class named "foo", which implies large commonalities of
syntax/implementation between classes, methods, operators, and ordinary
functions [1]... hee hee...)

Mike Lazzaro
Cognitivity (http://www.cognitivity.com/)


[1] ...which implies that all Perl6 operators and functions can (must?)
be implemented as flyweight classes with interfaces that define their
properties/attributes/arguments/contexts, but that's a Perl6 <-->
Parrot thing.

Michael G Schwern

unread,
Oct 1, 2002, 3:33:04 PM10/1/02
to Michael Lazzaro, perl6-l...@perl.org
On Tue, Oct 01, 2002 at 11:51:02AM -0700, Michael Lazzaro wrote:
> >This comes down to an OO philosophy issue. If Perl 6 wants a strict OO
> >style, don't put in a loophole. If they want to leave some room to
> >play,
> >put in the ability to turn some of the strictness off.
>
> I guess what bothers me is the loophole issue, sort of... in specific,
> who gets to decide whether a given interface method is optional.

If we do it loosely, the subclasser decides if they want to follow the
interface, since most violations of an interface are done because it's being
used in an unforseen manner. But they have to explicitly say they're
violating it.

I can't see any good reason why an interface author would want to make their
interface optional.

If we do it strictly, interfaces are not optional.

Perhaps a way to sharpen the focus on this is to expand the discusson of
strictness to include not just method prototypes but Design-By-Contract
features as well (pre and post conditions and invariants). Should DBC
conditions be overridable? Since it's not terribly useful to override a
signature only to be stopped by a pre-condition.

Taken as a whole, I'm leaning towards no. Interfaces and conditions should
be strict. They can be gotten around using delegation, which should be
built into Perl 6 anyway.


> >I don't think that the addition of an optional parameter
> >violates any substitution principle: users of the base-class
> >interface couldn't use the extra params (because they're not in
> >the interface); but a user of the derived-class's interface
> >can use the extra power (because they are in that interface).
> >A derived class is always allowed to add things (thus, you can
> >weaken preconditions, stengthen postconditions, add extra
> >methods, return a more specific result, ...; but you can't
> >strengthen a precondtion, nor weaken a postcondition, etc.)
>
> Agreed. If we had some concept like "strict" vs. "overridable"
> interfaces, should "strict" prevent this, too, or are extra, optional
> parameters always allowed as a special case (under the assumption that
> they can't hurt anything that doesn't know about them?)

Unless someone can come up with a practical case of adding parameters which
violates the interface, I'd say there's no problem, strict or no strict.


> My musing is that the behavior of a class in different contexts is
> itself an interface, in the sense of being a contract between a
> class/subclass and it's users

Ah HA! Contract! Return values can be enforce via a simple DBC post
condition, no need to invent a whole new return value signature.


--

Michael G. Schwern <sch...@pobox.com> http://www.pobox.com/~schwern/
Perl Quality Assurance <per...@perl.org> Kwalitee Is Job One

And if you don't know Which To Do
Of all the things in front of you,
Then what you'll have when you are through
Is just a mess without a clue.
Of all the best that can come true
If you know What and Which and Who.

Trey Harris

unread,
Oct 1, 2002, 3:43:22 PM10/1/02
to Michael G Schwern, David Whipp, Michael Lazzaro, perl6-l...@perl.org
In a message dated Mon, 30 Sep 2002, Michael G Schwern writes:

> On Mon, Sep 30, 2002 at 06:04:28PM -0700, David Whipp wrote:
> > On a slightly different note, if we have interfaces then I'd really
> > like to follow the Eiffel model: features such as renaming methods
> > in the derived class may seem a bit strange; but they can be useful
> > if you have have name-conflicts with multiple inheritance.
>
> I'm not familiar with the Eiffel beyond "it's the DBC language and it's
> French", but wouldn't this simply be covered by aliasing?

No, because this only gives you a second name for the method, it does not
obliterate the meaning of the first. The example Damian uses in his OO
class (when he discusses Class::Delegation) is a Car which inherits from
Vehicle (which has an action C<method drive(int $speed)>, which causes the
car to move) and also inherits from MP3_Player (which has an accessor
C<method drive(int $id)> which sets which media spindle to use).

It's incorrect to use just the C<Vehicle::drive()> method, it's incorrect
to use just the C<MP3_Player::drive()> method, it's incorrect to call both
(vehicular acceleration would cause the MP3 player to change disks). You
need both capabilities, but you need them separately.

You want something like

class Car is Vehicle renames(drive => accel)
is MP3_Player renames(drive => mp3_drive);

Either of those renamings is, of course, optional, in which case drive()
refers to the non-renamed one when referring to a Car object.

But later on, if some code does

Vehicle $mover = getNext(); # returns a Car
$mover.drive(5);

It should call C<Vehicle::drive()> on C<$mover>, that is,
C<$mover.accel()>.

See why aliasing doesn't solve this?

It can get more complicated, too. Say you want to do this (I don't know
if this will be possible, but it could be):

class DoublyLinkedList is LinkedList
is LinkedList
renames($.head => $.tail,
nextNode => prevNode
Node::$.next => Node::$.prev);

What's going on here? We're inheriting from C<LinkedList> twice. The
first time, we just accept it wholesale, including its inner Node class
which contains a $.data and a $.next reference. The second time, we
rename the $.head reference to $.tail (along with its associated method
head() to tail()), we rename its nextNode() method to prevNode(), and we
rename *its* version of the inner Node class to make $.next into $.prev.
The Node::$.data attribute is still shared.

Redefine insert() and delete() so that it deals with both the next node
and the previous node, and you're done. If some $variable of type
LinkedList was assigned a DoublyLinkedList, a call to
C<$variable.nextNode> would call the un-redefined nextNode, which is
correct. If you redefined *both* C<nextNode()>s, you'd probably call the
first one in that situation. But who knows....

Supporting repeated inheritance and multiple inheritance with partial
redefinition opens a huge ball of wax as far as complicated inheritance
rules that I don't know Damian or Larry have any interest in fleshing out,
but it could be made to work. Try *that* with aliasing.

Trey

Michael G Schwern

unread,
Oct 1, 2002, 4:19:52 PM10/1/02
to Trey Harris, David Whipp, Michael Lazzaro, perl6-l...@perl.org
On Tue, Oct 01, 2002 at 03:43:22PM -0400, Trey Harris wrote:
> You want something like
>
> class Car is Vehicle renames(drive => accel)
> is MP3_Player renames(drive => mp3_drive);
>
> Either of those renamings is, of course, optional, in which case drive()
> refers to the non-renamed one when referring to a Car object.
>
> But later on, if some code does
>
> Vehicle $mover = getNext(); # returns a Car
> $mover.drive(5);
>
> It should call C<Vehicle::drive()> on C<$mover>, that is,
> C<$mover.accel()>.
>
> See why aliasing doesn't solve this?

Ahh, because Perl has to know that when $mover is used as a Vehicle it
uses Car.accel but when used as an MP3_Player it calls Car.mp3_drive.
Clever!


--

Michael G. Schwern <sch...@pobox.com> http://www.pobox.com/~schwern/
Perl Quality Assurance <per...@perl.org> Kwalitee Is Job One

If I got something to say, I'll say it with lead.
-- Jon Wayne

Noah White

unread,
Oct 6, 2002, 1:49:26 AM10/6/02
to Michael G Schwern, Michael Lazzaro, perl6-l...@perl.org

On Monday, September 30, 2002, at 08:23 PM, Michael G Schwern wrote:

> OTOH, Java interfaces have a loophole which is considered a design
> mistake.
> An interface can declare some parts of the interface optional and then
> implementors can decide if they want to implement it or not. The
> upshot
> being that if you use a subclass in Java you can't rely on the optional
> parts being there.
>

Say what?!? I don't think so. If a JAVA class which implements an
interface does not declare all of the methods of the interface then
that class will be abstract and you won't be able to instantiate a
concrete instance of it. You are guaranteed that any concrete instance
of a class which implements an interface will contain ALL methods
defined by the interface.

-Noah

Nicholas Clark

unread,
Oct 6, 2002, 4:39:39 PM10/6/02
to Michael Lazzaro, Trey Harris, Michael G Schwern, David Whipp, perl6-l...@perl.org
On Tue, Oct 01, 2002 at 04:01:26PM -0700, Michael Lazzaro wrote:
>
> >On Tue, Oct 01, 2002 at 03:43:22PM -0400, Trey Harris wrote:
> >>You want something like
> >>
> >> class Car is Vehicle renames(drive => accel)
> >> is MP3_Player renames(drive => mp3_drive);
>
> I *really* like this, but would the above be better coded as:

>
> class Car is Vehicle renames(drive => accel)
> has MP3_Player renames(drive => mp3_drive);
>
> .... implying a "container" relationship with automatic delegation?
> Among the other considerations is that if you simply said
>
> class Car is Vehicle has MP3_Player;
>
> the inheritance chain could assume that Car.drive === Vehicle.drive,
> because is-a (inheritance) beats has-a (containment or delegation). If
> you needed to, you should still be able to call $mycar.MP3_Player.drive
> to DWYM, too.

I don't think I like this. Assume that instead of an mp3 player my car
has a 007 CD autochanger.

then $car.drive is as we expect, Vehicle.drive, because inheritance beats
containment or delegation.

But I could get a nasty shock when I want to open the tray on the CD player,
call $car.eject, and the car fires me out through the sunroof.

I think that the first syntax

class Car::Q is Car renames(eject => ejector_seat)
is CD_Player renames(drive => cd_drive);

makes it more clear that I'd like to pick and choose which methods
the composite object gets from which parent.

Nicholas Clark
--
Even better than the real thing: http://nms-cgi.sourceforge.net/

Michael G Schwern

unread,
Oct 6, 2002, 9:57:40 PM10/6/02
to Noah White, Michael Lazzaro, perl6-l...@perl.org

This came up durning a talk at JAOO by Kevlin Henny entitled "Minimalism: A
Practical Guide to Writing Less Code" which is a nice talk, Java or not.
http://www.two-sdg.demon.co.uk/curbralan/papers.html

Slide 7, which is about obeying contracts, says:

Subclassing and implemented interfaces should follow substitutability

Unsupported operations or operations that do a
little less or expect a little extra add complexity

and he went off on a short tangent during the talk about optional operations
in Java.

It is possible in Java to declare methods to be an "optional operation".
This means the subclass may or may not implement that method and if you try
to use an unimplemented method an UnsupportedOperationException is thrown.

Effectively, this means that for every optional method you want to use,
you've got to wrap it in a try block to catch the
UnsupportedOperationException, recover and try to do something else if it's
not there. Makes using an optional operation complicated and error prone.

In effect, an optional interface is declaring "this method may or may not
exist" which ain't that useful.

I can't find the syntax or this or when it was introduced, might be 1.2, but
I see it mentioned in the Collection API and tutorial docs:

http://java.sun.com/docs/books/tutorial/collections/interfaces/collection.html

The Collection interface is shown below:
public interface Collection {
// Basic Operations
int size();
boolean isEmpty();
boolean contains(Object element);
boolean add(Object element); // Optional
boolean remove(Object element); // Optional
Iterator iterator();

http://java.sun.com/docs/books/tutorial/collections/interfaces/

To keep the number of core collection interfaces manageable, the JDK
doesn't provide separate interfaces for each variant of each collection
type. (Among the possible variants are immutable, fixed-size, and
append-only.) Instead, the modification operations in each interface are
designated optional: a given implementation may not support some of
these operations. If an unsupported operation is invoked, a collection
throws an UnsupportedOperationException . Implementations are
responsible for documenting which of the optional operations they
support. All of the JDK's general purpose implementations support all
of the optional operations.

http://java.sun.com/j2se/1.4.1/docs/api/java/util/Collection.html

Method Summary

 boolean add(Object o)
          Ensures that this collection contains the specified element
(optional operation).

 boolean addAll(Collection c)
          Adds all of the elements in the specified collection to this
collection (optional operation).

 void clear()
          Removes all of the elements from this collection (optional
operation).

 boolean contains(Object o)
          Returns true if this collection contains the specified element.


I don't know basic Java syntax worth a damn, but I know its dirty little
secrets. ;)


--

Michael G. Schwern <sch...@pobox.com> http://www.pobox.com/~schwern/
Perl Quality Assurance <per...@perl.org> Kwalitee Is Job One

It's Absinthe time!

Noah White

unread,
Oct 6, 2002, 11:57:51 PM10/6/02
to Daniel B. Boorstein, Michael G Schwern, Michael Lazzaro, perl6-l...@perl.org

On Sunday, October 6, 2002, at 06:17 PM, Daniel B. Boorstein wrote:
[SNIP]

> I think there may be some confusion here. In java, there's no special
> syntax
> to declare a method an optional part of the interface. All concrete
> classes
> that implement the Collection interface still must define full-bodied
> C<add(Object element)> methods. It just so happens that by convention
> some
> classes simply throw an UnsupportedOperationException, perhaps like so:
>
> public class MyStaticCollection implements Collection {
> ...
> public boolean add (Object element) {
> throw new UnsupportedOperationException("add not supported");
> }
> ...
> }

Yes, this is true and is a common way to stub out methods you may
choose not to provide functionality for. For example, your code
implements a JDK 1.2 interface, then you subsequently switch to the 1.4
VM implementation for which that interface's API has changed and there
are now 14 more methods to be implemented for which you don't care
about :-) You still need to provide the method signatures in your
concrete class, but as in your example above you can throw an
UnsupportedOperationException within that method. Or as Michael
pointed out in the Collections interface, the add() method of a
read-only Collection implementation will throw an
UnsupportedOperationException.

I wouldn't call it a dirty little secret as Michael put it :-). This
is the right thing to do within the context of a contract. The contract
does not guarantee that method functionality implemented by a concrete
class does exactly a certain thing a certain way ( I'd like to see the
language that does!). It only guarantees return type, optional
parameters to accept and any CHECKED exceptions that need be thrown
(and _importantly_, caught by the invoker), not actually what goes on
in the method. If it did it wouldn't be an interface :-) Now, an
UnsuppoertedOperationException is an UNCHECKED (subclass of
RuntimeException) exception.

The weakness if any lies here. It would be nice for the compiler to
tell me that I've invoked a method which is going to throw that
exception, so I would know that I used a method that I probably
shouldn't be using before it actually gets tapped at runtime which is
too late and goes *boom*.

-Noah


Andy Wardley

unread,
Oct 7, 2002, 3:51:23 AM10/7/02
to Nicholas Clark, Michael Lazzaro, Trey Harris, Michael G Schwern, David Whipp, perl6-l...@perl.org
Nicholas Clark wrote:
> I think that the first syntax
>
> class Car::Q is Car renames(eject => ejector_seat)
> is CD_Player renames(drive => cd_drive);
>
> makes it more clear that I'd like to pick and choose which methods
> the composite object gets from which parent.

But now you've turned composition back into inheritance, and I think it's
important to be able to distinguish between the two.

The car is definately not a CD player, it just has one.

I think we need a more flexible syntax for specifying how interfaces
should be constructed in the case of composed objects, rather than
turning composition into inheritance to avoid the problem.


A

Daniel B. Boorstein

unread,
Oct 6, 2002, 6:17:37 PM10/6/02
to Michael G Schwern, Noah White, Michael Lazzaro, perl6-l...@perl.org
On Sunday 06 October 2002 09:57 pm, Michael G Schwern wrote:
> On Sun, Oct 06, 2002 at 01:49:26AM -0400, Noah White wrote:
> > >OTOH, Java interfaces have a loophole which is considered a design
> > >mistake.
> > >An interface can declare some parts of the interface optional and then
> > >implementors can decide if they want to implement it or not. The
> > >upshot
> > >being that if you use a subclass in Java you can't rely on the optional
> > >parts being there.
> >
> > Say what?!? I don't think so. If a JAVA class which implements an
> > interface does not declare all of the methods of the interface then
> > that class will be abstract and you won't be able to instantiate a
> > concrete instance of it. You are guaranteed that any concrete instance
> > of a class which implements an interface will contain ALL methods
> > defined by the interface.
>

[snip]

>
> It is possible in Java to declare methods to be an "optional operation".
> This means the subclass may or may not implement that method and if you try
> to use an unimplemented method an UnsupportedOperationException is thrown.
>
> Effectively, this means that for every optional method you want to use,
> you've got to wrap it in a try block to catch the
> UnsupportedOperationException, recover and try to do something else if it's
> not there. Makes using an optional operation complicated and error prone.

To be clear, UnsupportedOperationException is a subclass of RuntimeException,
and therefore one is not required to wrap a try around methods that throw it.

>
> In effect, an optional interface is declaring "this method may or may not
> exist" which ain't that useful.
>
> I can't find the syntax or this or when it was introduced, might be 1.2,
> but I see it mentioned in the Collection API and tutorial docs:
>
> http://java.sun.com/docs/books/tutorial/collections/interfaces/collection.h
>tml
>
> The Collection interface is shown below:
> public interface Collection {
> // Basic Operations
> int size();
> boolean isEmpty();
> boolean contains(Object element);
> boolean add(Object element); // Optional
> boolean remove(Object element); // Optional
> Iterator iterator();
>

I think there may be some confusion here. In java, there's no special syntax

to declare a method an optional part of the interface. All concrete classes
that implement the Collection interface still must define full-bodied
C<add(Object element)> methods. It just so happens that by convention some
classes simply throw an UnsupportedOperationException, perhaps like so:

public class MyStaticCollection implements Collection {
...
public boolean add (Object element) {
throw new UnsupportedOperationException("add not supported");
}
...
}

This is really no different than the following from Tie::Handle:

sub READ {
my $pkg = ref $_[0];
croak "$pkg doesn't define a READ method";
}

No special syntax, just convention enforced by the method implementations.

- Dan Boorstein

Michael G Schwern

unread,
Oct 8, 2002, 4:55:49 PM10/8/02
to Daniel B. Boorstein, Noah White, Michael Lazzaro, perl6-l...@perl.org
On Sun, Oct 06, 2002 at 06:17:37PM -0400, Daniel B. Boorstein wrote:
> I think there may be some confusion here. In java, there's no special syntax
> to declare a method an optional part of the interface. All concrete classes
> that implement the Collection interface still must define full-bodied
> C<add(Object element)> methods. It just so happens that by convention some
> classes simply throw an UnsupportedOperationException, perhaps like so:

AHHHH! No wonder I couldn't find any syntax for it! Thanks for clearing
that up.

Still, the objections still hold, though now it's a stylistic objection
rather than syntactic. It's disturbing that they'd put these optional
methods into the core Java API, thereby encouraging their use ("Sun did it,
so I can to!"). Cannonizing the idea weakens the whole concept of an
interface and contract.

It really ought to be one of those "sure you can do this, but please don't"
things.


--

Michael G. Schwern <sch...@pobox.com> http://www.pobox.com/~schwern/
Perl Quality Assurance <per...@perl.org> Kwalitee Is Job One

You see, in this world there's two kinds of people. Those with loaded
guns, and those who dig. Dig.
-- Blondie, "The Good, The Bad And The Ugly"

Michael G Schwern

unread,
Oct 8, 2002, 5:00:20 PM10/8/02
to Noah White, Daniel B. Boorstein, Michael Lazzaro, perl6-l...@perl.org
On Sun, Oct 06, 2002 at 11:57:51PM -0400, Noah White wrote:
> I wouldn't call it a dirty little secret as Michael put it :-).
> This is the right thing to do within the context of a contract. The
> contract does not guarantee that method functionality implemented by a
> concrete class does exactly a certain thing a certain way ( I'd like to see
> the language that does!).

Oddly enough, JUnit (and in the Perl world Test::Class and Test::Unit) can
do it with inherited tests. Subclasses must pass their parent's tests, so
yes, you can guarantee method implementations, just not with an interface
contract.

Unfortunately, Java doesn't ship with JUnit nor do Java libraries usually
ship with tests nor does a simple convention to run them nor an expectation
that the user will run the tests before installing. Score one for Perl. :)


--

Michael G. Schwern <sch...@pobox.com> http://www.pobox.com/~schwern/
Perl Quality Assurance <per...@perl.org> Kwalitee Is Job One

Please Captain, not in front of the Klingons.

Michael G Schwern

unread,
Oct 8, 2002, 5:36:49 PM10/8/02
to Trey Harris, Daniel B. Boorstein, Noah White, Michael Lazzaro, perl6-l...@perl.org
On Tue, Oct 08, 2002 at 05:03:26PM -0400, Trey Harris wrote:
> > It really ought to be one of those "sure you can do this, but please don't"
> > things.
>
> It's a RuntimeException. You can't require that all RuntimeExceptions be
> declared if thrown;
<snip>
> You can subclass RuntimeException. So if Sun hadn't provided an
> UnsupportedOperationException, anyone else could easily have done so.

I'm not objecting to the fact that it's a runtime exception [1] or that it's
possible to do such a thing. I'm objecting to the fact that it's an
exception at all since it adds uncertainty into what should otherwise be a
guaranteed interface and that this uncertainty is put in the core library of
the language.

Because Sun did it it's now Officially OK, even if that's not what they
ment. More so in the Java world than in Perl, things you do in the core API
become canonized. "Because that's how Sun does it" carries a lot of weight.
In Perl it's often "that's how (C|Bourne Shell|$popular_module) does it".

Programmers parroting the design of a popular API is common and can be used
for Good or Evil.


[1] It would be less worse [2] as a compile-time exception.
[2] This is different than "better". ;)

--

Michael G. Schwern <sch...@pobox.com> http://www.pobox.com/~schwern/
Perl Quality Assurance <per...@perl.org> Kwalitee Is Job One

I don't get it. Must be art.

Trey Harris

unread,
Oct 8, 2002, 5:03:26 PM10/8/02
to Michael G Schwern, Daniel B. Boorstein, Noah White, Michael Lazzaro, perl6-l...@perl.org
In a message dated Tue, 8 Oct 2002, Michael G Schwern writes:

> On Sun, Oct 06, 2002 at 06:17:37PM -0400, Daniel B. Boorstein wrote:
> > I think there may be some confusion here. In java, there's no special syntax
> > to declare a method an optional part of the interface. All concrete classes
> > that implement the Collection interface still must define full-bodied
> > C<add(Object element)> methods. It just so happens that by convention some
> > classes simply throw an UnsupportedOperationException, perhaps like so:
>
> AHHHH! No wonder I couldn't find any syntax for it! Thanks for clearing
> that up.
>
> Still, the objections still hold, though now it's a stylistic objection
> rather than syntactic. It's disturbing that they'd put these optional
> methods into the core Java API, thereby encouraging their use ("Sun did it,
> so I can to!"). Cannonizing the idea weakens the whole concept of an
> interface and contract.
>
> It really ought to be one of those "sure you can do this, but please don't"
> things.

It's a RuntimeException. You can't require that all RuntimeExceptions be
declared if thrown; otherwise, every method would have to declare "throws
OutOfMemoryException, CannotLoadClassException,
TheEndTimeIsUponUsException, ..." for every single runtime error. You


can subclass RuntimeException. So if Sun hadn't provided an
UnsupportedOperationException, anyone else could easily have done so.

And they'll be able to in Perl, too, whatever you do. I often code

method foo {
die "Abstract method foo not implemented in concrete class" .
(ref $_[0] || $_[0]) . ", died";
}

In my abstract superclasses, which is the very same thing.

Trey

Roland Schemers

unread,
Oct 8, 2002, 6:23:16 PM10/8/02
to Michael G Schwern, Trey Harris, Daniel B. Boorstein, Noah White, Michael Lazzaro, perl6-l...@perl.org
Take a look at:

http://java.sun.com/products/jdk/1.2/docs/guide/collections/designfaq.html

Either you agree with the answer to "Core Interfaces" questions 1 and 2 or
you don't. There are tradeoffs to be made, and I think they made some
reasonable choices, though others are free to think otherwise :)

roland

Larry Wall

unread,
Oct 10, 2002, 2:39:03 PM10/10/02
to Michael G Schwern, Simon Cozens, perl6-l...@perl.org
On Mon, 30 Sep 2002, Michael G Schwern wrote:

: On Tue, Oct 01, 2002 at 01:36:19AM +0100, Simon Cozens wrote:
: > sch...@pobox.com (Michael G Schwern) writes:
: > > method _do_internal_init ($num) is private {
: >
: > Just thinking aloud, would
: > sub foo is method is private is integer is fungible {
: >
: > be better written as
: > sub foo is fungible private integer method {
: >
: > or not?

It's potentially ambiguous. Here's a bad example, but there are probably
better ones:

my $foo is rw cmp "";

Plus we have to worry about arguments to properties, if we allow
anything other than (). I'd personally like to see some properties
that can take a closure as their argument, but the parser would have
to know that in advance or the "method" property above would slurp
up the subroutine block by accident. Or the sub block itself needs
a keyword.

: How about seperated by commas, like any other list?


:
: method foo is fungible, private, integer {

Is ambiguous:

my ($foo is foo, bar, $bar is baz) = (1,2);

Also, precedence of comma with respect to assignment causes problems.

We may be able to relax this later somehow, but for now we're saying
that "is...is...is..." isn't all that onerous.

To which the only correct reply is, "but...but...but..." :-)

Larry

Larry Wall

unread,
Oct 10, 2002, 3:38:39 PM10/10/02
to Andy Wardley, Nicholas Clark, Michael Lazzaro, Trey Harris, Michael G Schwern, David Whipp, perl6-l...@perl.org

Yes, that's important. If you've got a CD_Player *object*, it doesn't
do anyone any good to pretend it's a car *object*. We too often
lose sight of the fact that objects should behave like objects. That's
what OO really means, after all. OO isn't about inheritance

Anyway, I don't see offhand why composition can't simply be done with
attributes as it is in C++, especially since attributes manifest as
methods outside the class. I don't think $car.cd.eject() is all that
horrible to contemplate.

Larry

Michael Lazzaro

unread,
Oct 11, 2002, 7:29:27 PM10/11/02
to perl6-l...@perl.org

On Friday, October 11, 2002, at 04:11 PM, Larry Wall wrote:
> has Nose $.snout;
> has Ear @.ears is cut("long");
> has Leg @.legs;
> has Tail $.tail is cut("short");
>
> method Wag () {...}
> }

What's the rationale again for the dot in $.snout? Does it imply that
it should be

method .Wag () {...}

to match?

MikeL

Larry Wall

unread,
Oct 11, 2002, 7:11:15 PM10/11/02
to Andy Wardley, Nicholas Clark, Michael Lazzaro, Trey Harris, Michael G Schwern, David Whipp, perl6-l...@perl.org
On Thu, 10 Oct 2002, Larry Wall wrote:
: Anyway, I don't see offhand why composition can't simply be done with

: attributes as it is in C++, especially since attributes manifest as
: methods outside the class. I don't think $car.cd.eject() is all that
: horrible to contemplate.

By the way, ever since we came up with "attr" in Zurich, I've been
hating it more and more. I'm thinking that "has" reads a lot better:

class Dog is Mammal {


has Nose $.snout;
has Ear @.ears is cut("long");
has Leg @.legs;
has Tail $.tail is cut("short");

method Wag () {...}
}

Or, along the lines of "my" lists:

class Dog is Mammal {
has (
Nose $.snout,
Ear @.ears is cut("long"),
Leg @.legs,
Tail $.tail is cut("short"),
);

method Wag () {...}
}

Larry

Larry Wall

unread,
Oct 11, 2002, 8:02:02 PM10/11/02
to Michael Lazzaro, perl6-l...@perl.org
On Fri, 11 Oct 2002, Michael Lazzaro wrote:

Yes, that's part of it, presuming you actually meant:

method .snout () {...}

It also doesn't look like either a lexical or a global when you use
it within the method. I always hated that about C++.

I suppose it could be argued that the . is redundant within a "has",
but I kinda like the consistency. It could also be argued that
the '$' should be dropped on scalar attributes, but that's another
consistency thing. You can certainly drop it within the methods,
since there's also the accessor methods.

Larry

Larry Wall

unread,
Oct 11, 2002, 8:08:10 PM10/11/02
to Michael Lazzaro, perl6-l...@perl.org
On Fri, 11 Oct 2002, Larry Wall wrote:
: You can certainly drop it within the methods,

: since there's also the accessor methods.

But I should point out that there's a semantic difference between
$.foo and .foo, in that $.foo is guaranteed to get my copy of the
attribute, while .foo might just go haring off after a virtual method
in a subclass, if the subclass puts a wrapper method around this
class's .foo method.

Larry

Jonathan Scott Duff

unread,
Oct 11, 2002, 10:18:52 PM10/11/02
to Larry Wall, Michael Lazzaro, perl6-l...@perl.org
On Fri, Oct 11, 2002 at 05:02:02PM -0700, Larry Wall wrote:
> On Fri, 11 Oct 2002, Michael Lazzaro wrote:
> : On Friday, October 11, 2002, at 04:11 PM, Larry Wall wrote:
> : > has Nose $.snout;
> : > has Ear @.ears is cut("long");
> : > has Leg @.legs;
> : > has Tail $.tail is cut("short");
> : >
> : > method Wag () {...}
> : > }

I like "has" quite a bit.

> :
> : What's the rationale again for the dot in $.snout? Does it imply that
> : it should be
> :
> : method .Wag () {...}
> :
> : to match?
>
> Yes, that's part of it, presuming you actually meant:
>
> method .snout () {...}

Actually, I think he meant

method &.Wag () { ... }

"Attribute declarations have their dots, why not methods?" or
something to that effect.

-Scott
--
Jonathan Scott Duff
du...@cbi.tamucc.edu

Nicholas Clark

unread,
Oct 12, 2002, 10:13:13 AM10/12/02
to Michael G Schwern, Noah White, Daniel B. Boorstein, Michael Lazzaro, perl6-l...@perl.org
On Tue, Oct 08, 2002 at 05:00:20PM -0400, Michael G Schwern wrote:
> Unfortunately, Java doesn't ship with JUnit nor do Java libraries usually
> ship with tests nor does a simple convention to run them nor an expectation
> that the user will run the tests before installing. Score one for Perl. :)

I blame that Schwern character, and his partner in crime, Chromatic. They keep
encouraging us to use more 'tests'; Very bad habit - I mean, with more tests
we'll probably be shipping software with less bugs, and where's that going to
lead? I tell you, less bugs mean less jobs for us programmers, and that's not
good. We'll have trouble occupying all the time that will free up. We might
even be forced to do fun stuff. :-)

0 new messages