[comp.lang.eiffel] Unification: Class=Type=Module

richieb@bony1.bony.com (Richard Bielak) (04/23/91)

One of the things I liked about "Object Oriented Software Construction"
by B. Meyer, was the idea that a class is both a type and a module.
This idea clears up the confusion as to whether inheritance extends or
specializes.

When a class is considered to be a type, inheritance specializes the
type. The descendent type is type-compatible with fewer things, so it
is more specialized.

When a class is considered to be a module, inheritance adds more
routines and attributes. Since the class can do more things it has
been  extended.

I also like the "cleanness" and simplicity of this idea. 

I am curious whether other people think about this, and whether such
"unification" has any disadvantages.

...richie
-- 
*-----------------------------------------------------------------------------*
| Richie Bielak  (212)-815-3072    | Programs are like baby squirrels. Once   |
| Internet:      richieb@bony.com  | you pick one up and handle it, you can't |
| Bang:       uunet!bony1!richieb  | put it back. The mother won't feed it.   |

davis@barbes.ilog.fr (Harley Davis) (04/24/91)

In article <1991Apr23.142800.12215@bony1.bony.com> richieb@bony1.bony.com (Richard Bielak) writes:

   One of the things I liked about "Object Oriented Software Construction"
   by B. Meyer, was the idea that a class is both a type and a module.
   This idea clears up the confusion as to whether inheritance extends or
   specializes.

   When a class is considered to be a type, inheritance specializes the
   type. The descendent type is type-compatible with fewer things, so it
   is more specialized.

   When a class is considered to be a module, inheritance adds more
   routines and attributes. Since the class can do more things it has
   been  extended.

   I also like the "cleanness" and simplicity of this idea. 

   I am curious whether other people think about this, and whether such
   "unification" has any disadvantages.

For me, a module is a higher-level structuring tool than a class.  A
module pulls together a set of classes, functions, methods, and local
data which form a coherent design unit.  A class is just one of the
possible implementation choices for a module; not everything need be
tied to a class.  This is approach taken by, for example, EuLisp and
Le-Lisp version 16.

While classes could be identified with modules, I find that in real
cases this forces too fine-grained a separation on the implementation.
It is difficult to define a module containing an entire class
hierarchy with associated operations, all exported as a unit.

In this view of the world, the two kinds of inheritance provided by
importing modules and subclassing more or less solve the two goals you
mention separately - ie, subclassing specializes, and module
importation extends.  However, I don't see this correspondence as
being essential.

-- Harley Davis
--
------------------------------------------------------------------------------
nom: Harley Davis			ILOG S.A.
net: davis@ilog.fr			2 Avenue Gallie'ni, BP 85
tel: (33 1) 46 63 66 66			94253 Gentilly Cedex, France

schwartz@groucho.cs.psu.edu (Scott Schwartz) (04/25/91)

richieb@bony1.bony.com (Richard Bielak) writes:
| One of the things I liked about "Object Oriented Software Construction"
| by B. Meyer, was the idea that a class is both a type and a module.
| This idea clears up the confusion as to whether inheritance extends or
| specializes.
| 
| When a class is considered to be a type, inheritance specializes the
| type. The descendent type is type-compatible with fewer things, so it
| is more specialized.
| 
| When a class is considered to be a module, inheritance adds more
| routines and attributes. Since the class can do more things it has
| been  extended.
| 
| I also like the "cleanness" and simplicity of this idea. 
| 
| I am curious whether other people think about this, and whether such
| "unification" has any disadvantages.

Since no one else has stood forth on the issue, I will.  (Let me admit
in advance that I've never written an Eiffel program in my life; these
comments are motivated by experience with C++.  If a free eiffel
compiler were available, I'd probably use it.)

I don't much like using classes as modules.  They seem well suited to
building abstract data types, which means they do some encapsulation,
but that is no substitute for a real package system that lets you
encapsulate a group of ATDs.

You mention two ways to use inheritance.  It seems to me that these
two goals often get in each other's way; as a result there is real
disagreement on what inheritance is all about (I recall a paper
"inheritance is not subtyping" in a recent TOPLAS, for example.)
Eiffel's use of covariance and conditional assignment makes the kind
of extensibility that class-as-module requires possible -- it's much
harder in C++ where both of those are forbidden by the type system.

I feel like modularization is more useful than subtyping.  In that
light, I agree with lots of Wirth's design choices in Oberon.

sakkinen@jyu.fi (Markku Sakkinen) (04/25/91)

In article <DAVIS.91Apr24143741@barbes.ilog.fr> davis@barbes.ilog.fr (Harley Davis) writes:
>
>In article <1991Apr23.142800.12215@bony1.bony.com> richieb@bony1.bony.com (Richard Bielak) writes:
>
>   One of the things I liked about "Object Oriented Software Construction"
>   by B. Meyer, was the idea that a class is both a type and a module.
>   ...

I think this is essentially the "orthodox" object-oriented attitude
in general.

>   ...
>   I am curious whether other people think about this, and whether such
>   "unification" has any disadvantages.
>
>For me, a module is a higher-level structuring tool than a class.  A
>module pulls together a set of classes, functions, methods, and local
>data which form a coherent design unit.  A class is just one of the
>possible implementation choices for a module; not everything need be
>tied to a class.  This is approach taken by, for example, EuLisp and
>Le-Lisp version 16.
>
>While classes could be identified with modules, I find that in real
>cases this forces too fine-grained a separation on the implementation.
>It is difficult to define a module containing an entire class
>hierarchy with associated operations, all exported as a unit.
> ...

In conventional OOP, an entire class hierarchy is certainly not
a unit or module.  In fact, open-endedness for inheritance is perhaps
_the_ strong point of OO reusability.

Otherwise, I agree with Davis against the more orthodox view.
Thus, the package/module facilities of e.g. Ada and Modula-2,
when wisely used, are more versatile than the "one type at a time"
approach of CLU (the original ADT language) and most OOPL's.

Also, in typical OOPL's, every operation has exactly one "participant"
object that is in a distinguished role: the owner or "self";
any other "participants" are considered arguments.
I suggest that as many operations as possible should be defined
_on_ classes instead of _in_ them, i.e. without a distinguished
participant.  On the other hand, there are situations which crave
for more than one "owner" in an operation:  just look at the
unnatural way in which ordinary arithmetic operations are defined
in Smalltalk.

I have not read about any object-oriented language that would allow
several owners in an operation (unless the specification language
DisCo is counted).  In the generic functions (multi-methods)
of CLOS, the _selection_ of actual method(s) to be invoked can be based
on more than one argument, but in the _execution_ there is only
one "self".

Apologies if I am repeating some of my earlier ramblings too much ...

Markku Sakkinen
Department of Computer Science and Information Systems
University of Jyvaskyla (a's with umlauts)
PL 35
SF-40351 Jyvaskyla (umlauts again)
Finland
          SAKKINEN@FINJYU.bitnet (alternative network address)

barmar@think.com (Barry Margolin) (04/26/91)

In article <1991Apr25.074758.6153@jyu.fi> sakkinen@jytko.jyu.fi (Markku Sakkinen) writes:
>I have not read about any object-oriented language that would allow
>several owners in an operation (unless the specification language
>DisCo is counted).  In the generic functions (multi-methods)
>of CLOS, the _selection_ of actual method(s) to be invoked can be based
>on more than one argument, but in the _execution_ there is only
>one "self".

This is incorrect, CLOS has no inherent notion of "self", neither at method
selection time nor during the execution of the methods.  All the parameters
are accessed by name.  WITH-SLOTS and WITH-ACCESSORS can be used to make
the slots of instances accessible as if they were variables, but this is
not done automatically, and can be done for more than one argument, or even
for something that isn't an argument (CLOS provides no information hiding
or visibility control -- everything is public, and programmers are expected
to use other mechanisms, such as packages to implement visibility control).

In generic functions where there's only one argument that is used to
control method selection, some people have a convention of calling the
argument SELF in the method definitions (in generic function definitions
it's preferable to use a more descriptive name).  There's nothing special
about this name, though; most OO programmers were trained using languages
that did have a distinguished "self", and have gotten used to thinking that
way.

--
Barry Margolin, Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

rick@tetrauk.UUCP (Rick Jones) (04/26/91)

In article <1991Apr23.142800.12215@bony1.bony.com> richieb@bony1.UUCP (Richard Bielak) writes:
>
>One of the things I liked about "Object Oriented Software Construction"
>by B. Meyer, was the idea that a class is both a type and a module.
>This idea clears up the confusion as to whether inheritance extends or
>specializes.
>
>When a class is considered to be a type, inheritance specializes the
>type. The descendent type is type-compatible with fewer things, so it
>is more specialized.
>
>When a class is considered to be a module, inheritance adds more
>routines and attributes. Since the class can do more things it has
>been  extended.
>
>I also like the "cleanness" and simplicity of this idea. 
>
>I am curious whether other people think about this, and whether such
>"unification" has any disadvantages.

I believe it is a powerful notion, and is of course related to the concept of
abstract data types.  Personally I find that using the principle that a class
represents an ADT is the best guide to deciding what the classes should be, and
what should go into them.  I also add a little of the "responsibility" concept
as well.

In fact, in the module/type duality, the "type" is really the abstract type
rather than the language type.  I feel that the current debates about types and
type systems are taking an extremely narrow view of the subject.  In reality,
type conformance is not just about whether an object should "understand the
messages", or whatever the metaphor is in the parlance of any particular
programming language;  this is a language implementor's rather restricted view
of the world.  For type conformance to be meaningful in terms of the overall
design of a program, the semantic effects of each operation applicable to a
type need to be consistent as well.

This is where the module/type principle really starts to make sense, so that
extensions of the module become specialisations of the ADT.  Eiffel's
inheritance of assertions assures conforming semantics (given that the
assertions are used properly), so type conformance contributes towards overall
program correctness.

In real situations, things are not always so simple, and module
extension/specialisation can make certain features of the inherited ADT
invalid, so the descendant is not fully type compatible (even seen as an ADT)
with its parent - e.g. the infamous polygon/rectangle case.  It is, however,
conformant in respect of the features which it does support.  This is one of
the issues which the extended type checking proposed for Eiffel will address.

-- 
Rick Jones, Tetra Ltd.  Maidenhead, Berks, UK
rick@tetrauk.uucp

Any fool can provide a solution - the problem is to understand the problem

jncs@uno.edu (04/26/91)

In article <1991Apr25.074758.6153@jyu.fi>, sakkinen@jyu.fi (Markku Sakkinen) writes:
>In article <DAVIS.91Apr24143741@barbes.ilog.fr> davis@barbes.ilog.fr (Harley Davis) writes:
>>
>>In article <1991Apr23.142800.12215@bony1.bony.com> richieb@bony1.bony.com (Richard Bielak) writes:
>>
>>   One of the things I liked about "Object Oriented Software Construction"
>>   by B. Meyer, was the idea that a class is both a type and a module.
>>   ...
>
>Otherwise, I agree with Davis against the more orthodox view.
>Thus, the package/module facilities of e.g. Ada and Modula-2,
>when wisely used, are more versatile than the "one type at a time"
>approach of CLU (the original ADT language) and most OOPL's.
>
>
>Markku Sakkinen

Using the module facilities in Ada and Modula2, I have always been of the mind
of using one module to represent one ADT. I have seen examples of modules
containing several abstractions, as well as modules inside of modules and I 
have yet to see what is gained by doing this; I do see what is lost : I cannot
not use one of the Abstractions without the others. I see an abstraction as 
just that, a functional model of data and behavior and as such I want to
put it as a library unit. 

I would like to see examples where the packaging of several abstractions, or
the nesting of modules is a proper abstraction modelling.

J. Nino
Computer Science Department
University of New Orleans

mario@cs.man.ac.uk (Mario Wolczko) (04/27/91)

In article <1991Apr23.142800.12215@bony1.bony.com>, richieb@bony1.bony.com (Richard Bielak) writes:
> 
> One of the things I liked about "Object Oriented Software Construction"
> by B. Meyer, was the idea that a class is both a type and a module.
> This idea clears up the confusion as to whether inheritance extends or
> specializes.
...
> I also like the "cleanness" and simplicity of this idea. 

I also like this idea, but unfortunately no existing object-oriented
language (to the best of my knowledge) supports it properly.  Eiffel,
Smalltalk and CLOS all go only half way; C++ is a little better, but
still short of the mark.

For a class to be a module it should have a clear separation between
interface and implementation, such that any compatible
reimplementation can be substituted without affecting "users" of that
class.  That's what module means: you can swap compatible modules with
impunity. 

When the "user" is a client class, most if not all OO languages
succeed in hiding implementation, but when the "user" is a subclass,
they fail miserably.  For example, all of Smalltalk, Eiffel and CLOS
allow direct access to all inherited instance variables, so that no
part of the internal representation can be hidden.  In contrast, C++
lets you declare an instance variable (member) to be private.

In none of these languages can you isolate a class from the choice of
superclasses made by its parent(s).  

Mario Wolczko

   ______      Dept. of Computer Science   Internet:      mario@cs.man.ac.uk
 /~      ~\    The University              uucp:      mcsun!ukc!man.cs!mario
(    __    )   Manchester M13 9PL          JANET:         mario@uk.ac.man.cs
 `-':  :`-'    U.K.                        Tel: +44-61-275 6146  (FAX: 6236)
____;  ;_____________the mushroom project___________________________________

jls@rutabaga.Rational.COM (Jim Showalter) (04/30/91)

]>Using the module facilities in Ada and Modula2, I have always been of the mind
]>of using one module to represent one ADT. I have seen examples of modules
]>containing several abstractions, as well as modules inside of modules and I 
]>have yet to see what is gained by doing this; I do see what is lost : I cannot
]>not use one of the Abstractions without the others. I see an abstraction as 
]>just that, a functional model of data and behavior and as such I want to
]>put it as a library unit. 
]>
]>I would like to see examples where the packaging of several abstractions, or
]>the nesting of modules is a proper abstraction modelling.

There are numerous occasions when what one is constructing is an
abstraction of sufficient complexity that it requires "helper" sub-
abstractions. There is no reason to assume that such sub-abstractions
have any use outside the immediate implementation: in cases where this
is true, placing such sub-abstractions in the library serves no useful
purpose, pollutes the namespace, and, in fact, somewhat unbundles the
main abstraction being implemented. In such cases, nesting the sub-
abstractions inside the main abstraction is clearly a superior approach.

Believing that there is necessarily a one-to-one correspondence between
abstractions of interest to clients and modules strikes me as simplistic,
particularly since the experiences of myself and of numerous customers
indicate that this tends often to not be the case.
--
* "Beyond 100,000 lines of code, you should probably be coding in Ada." *
*      - P.J. Plauger, Convener and Secretary of the ANSI C Committee   *
*                                                                       *
*                The opinions expressed herein are my own.              *