From: David Bakhash
Subject: making virtual functions in CL
Date: 
Message-ID: <wkhftv2k8u.fsf@mit.edu>
Hi,

I'm trying to figure out how to make a virtual function.  i.e. suppose I
have a CLOS class called `entry':

(defclass entry () ())

and I just want to insure that each entry has a method called `id' so
that for all subclasses of entry I can do:

(id my-entry)

and get back something.  I don't want to add a slot called `id' in entry
b/c that might be less efficient.  Actually, I'm not even sure that
this is possible in CL (and if it isn't, then that's a bit
dissappointing).  But is there a way?  Is it possible to use
`defgeneric' in order to do this?

thanks,
dave

From: ········@poboxes.com
Subject: Re: making virtual functions in CL
Date: 
Message-ID: <77j04p$c3n$1@nnrp1.dejanews.com>
In article <··············@mit.edu>,
  David Bakhash <·····@mit.edu> wrote:
> Hi,
>
> I'm trying to figure out how to make a virtual function.  i.e. suppose I

Virtual?  Where does this word come from?  (Any similarities to
a language whose name starts with a `C' are purely coincidental?)

> have a CLOS class called `entry':
>
> (defclass entry () ())
>
> and I just want to insure that each entry has a method called `id' so
> that for all subclasses of entry I can do:
>
> (id my-entry)
>
> and get back something.  I don't want to add a slot called `id' in entry
> b/c that might be less efficient.  Actually, I'm not even sure that
> this is possible in CL (and if it isn't, then that's a bit
> dissappointing).  But is there a way?

(defmethod id ((x entry)) 'something)

> Is it possible to use
> `defgeneric' in order to do this?

Yes, sure:

(defgeneric id (x)
  (:method ((x entry)) 'something))

>
> thanks,
> dave

No sweat,
Vassil.


Vassil Nikolov <········@poboxes.com> www.poboxes.com/vnikolov
(You may want to cc your posting to me if I _have_ to see it.)
   LEGEMANVALEMFVTVTVM  (Ancient Roman programmers' adage.)

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own    
From: ·······@kraut.bc.ca
Subject: Re: making virtual functions in CL
Date: 
Message-ID: <ucr9sz3s9m.fsf@soft.mercury.bc.ca>
David Bakhash <·····@mit.edu> writes:
> 
> I'm trying to figure out how to make a virtual function.
> i.e. suppose I have a CLOS class called `entry':
> 
> (defclass entry () ())
> 
> and I just want to insure that each entry has a method called `id'
> so that for all subclasses of entry I can do:
> 
> (id my-entry)

(defmethod id ((self entry))
   'entry-id)

(defmethod id ((self my-entry))
   'my-entry-id)

Joachim

-- 
·······@kraut.bc.ca      (http://www.kraut.bc.ca)
·······@mercury.bc.ca    (http://www.mercury.bc.ca)
From: Marco Antoniotti
Subject: Re: making virtual functions in CL
Date: 
Message-ID: <lwbtk0beaj.fsf@copernico.parades.rm.cnr.it>
Kent M Pitman <······@world.std.com> writes:

	...
> 
> I'm sure there's something in the MOP that will allow you to do what
> you want by making a metaclass that allows required methods.  It's not
> that unreasonable if you understand that it is isn't the answer to all
> the world's problems.  But don't expect too much of it.  Incidentally,
> Flavors (one ancestor of CLOS) had a :REQUIRED-METHODS (I think that
> was the name) in DEFFLAVOR (the DEFCLASS equivalent), and I think it
> did pretty much exactly what you wanted.  It didn't make it into CL
> for some reason--not sure why.

Maybe a simple reason is the fact the FLAVORS where essentially
'singly dispatching', while it is more complex to define such a thing
for a multi method?

> But IMO the name "virtual" is just
> C++ baggage that is only confusing in this query.  Dylan uses the
> term "virtual" correctly.  A virtual slot is about having a slot that
> is computed rather than reprsented explicitly (such as an AREA slot
> for a rectangle that already has LENGTH and WIDTH).  Virtual slots
> probably want to be required methods, but required methods are not all
> virtual slots.  And what you described was a required method, not
> a virtual slot.
> 
> Incidentally, DEFGENERIC is not the right place for this info.
> That would be a modularity violation, IMO.  It has no business
> knowing about who will implement things.  Not if it's REALLY
> a generic function.  it's about defining a protocol.  DEFCLASS
> is about saying how protocols defined elsewhere map into a
> certain situation.  More than one class might want to have required
> methods for a given generic function.  It would be goofy for a 
> generic function to have a list of those classes as if somehow
> it knew the nature of that patchwork quilt...

I have been thinking along these lines for some time. I.e. somehow
it'd be nice to have a PROTOCOL something (the term 'object' is too
overloaded :) ) which could tell some code checker (maybe the
compiler?!? :) ) that a certain set of methods ("belonging to the
protocol" - quotes mandatory for the time being) is "present" in the
system.

I have no idea how to provide such a thing. :)

Cheers

-- 
Marco Antoniotti ===========================================
PARADES, Via San Pantaleo 66, I-00186 Rome, ITALY
tel. +39 - (0)6 - 68 10 03 17, fax. +39 - (0)6 - 68 80 79 26
http://www.parades.rm.cnr.it
From: Barry Margolin
Subject: Re: making virtual functions in CL
Date: 
Message-ID: <c0Pn2.228$oD6.15990@burlma1-snr1.gtei.net>
In article <··············@copernico.parades.rm.cnr.it>,
Marco Antoniotti  <·······@copernico.parades.rm.cnr.it> wrote:
>
>Kent M Pitman <······@world.std.com> writes:
>
>	...
>> 
>> I'm sure there's something in the MOP that will allow you to do what
>> you want by making a metaclass that allows required methods.  It's not
>> that unreasonable if you understand that it is isn't the answer to all
>> the world's problems.  But don't expect too much of it.  Incidentally,
>> Flavors (one ancestor of CLOS) had a :REQUIRED-METHODS (I think that
>> was the name) in DEFFLAVOR (the DEFCLASS equivalent), and I think it
>> did pretty much exactly what you wanted.  It didn't make it into CL
>> for some reason--not sure why.
>
>Maybe a simple reason is the fact the FLAVORS where essentially
>'singly dispatching', while it is more complex to define such a thing
>for a multi method?

It would complicate it a bit -- in addition to specifying the name of the
required method, you would also have to indicate which parameter was
supposed to be specialized on a subclass of the class with the option.

However, IIRC, :REQUIRED-METHODS wouldn't really do what the original
poster wanted.  I think he wanted a way to require that every leaf class
define its own version of the method (e.g. a method that returns the name
of the class).  :REQUIRED-METHODS, like C++'s pure virtual functions,
simply require that some method applicable to the object be defined in
order for a class to be instantiated.  It might be defined in some
intermediate class, not necessarily the leaf class.  In C++, each
intermediate class can ensure that his descendents must redefine it by
declaring it private, but if any of them declares it public then it gets
inherited down the chain; there's nothing abstract base class definer can
do to prevent this.

>> But IMO the name "virtual" is just
>> C++ baggage that is only confusing in this query.  Dylan uses the
>> term "virtual" correctly.  A virtual slot is about having a slot that
>> is computed rather than reprsented explicitly (such as an AREA slot
>> for a rectangle that already has LENGTH and WIDTH).  Virtual slots
>> probably want to be required methods, but required methods are not all
>> virtual slots.  And what you described was a required method, not
>> a virtual slot.

What the original poster was describing is called, in C++, a "pure virtual
function".  As has been noted elsewhere, all methods in CLOS are virtual
(they dispatch on the dynamic type); it's the "purity" that the original
poster was really after -- this is the quality that requires a subclass to
redefine the method.

>I have been thinking along these lines for some time. I.e. somehow
>it'd be nice to have a PROTOCOL something (the term 'object' is too
>overloaded :) ) which could tell some code checker (maybe the
>compiler?!? :) ) that a certain set of methods ("belonging to the
>protocol" - quotes mandatory for the time being) is "present" in the
>system.

I think Xerox PARC's Aspect-Oriented Programming research includes things
like this.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Don't bother cc'ing followups to me.
From: Marco Antoniotti
Subject: For David Bakhash (Re: making virtual functions in CL)
Date: 
Message-ID: <lwaezkbe0v.fsf_-_@copernico.parades.rm.cnr.it>
NOISE

David (Bakhash), what is your true email address?

Cheers

-- 
Marco Antoniotti ===========================================
PARADES, Via San Pantaleo 66, I-00186 Rome, ITALY
tel. +39 - (0)6 - 68 10 03 17, fax. +39 - (0)6 - 68 80 79 26
http://www.parades.rm.cnr.it
From: Erik Naggum
Subject: Re: making virtual functions in CL
Date: 
Message-ID: <3125580309189239@naggum.no>
* ···@sevak.isi.edu (Thomas A. Russ)
| This is a useful semantic concept when one is defining abstract
| superclasses, ie, classes which are not expected to be instantiated
| directly.  This is typically done in order to have a common interface, or
| in situations where some portion of the functionality can be implemented
| by methods on the abstract class, but for which some additional concrete
| methods are required for proper functioning.
| 
| This does not seem like an unreasonable request.

  no, it isn't: it caused the concept of "interfaces" in Java.  however,
  the "virtual" _implementation_ of this request as found in C++ is
  inherently flawed and should not be replicated anywhere.

  there are many ways to enforce a protocol or interface.  a language may
  implement one way to do it, and that's all you get.  Common Lisp is not
  similarly constrained.  if you want to specify an interface that should
  cause all classes to implement their own methods, we should not look at
  how C++ was broken and put back toghether with duct tape -- the duct tape
  is not hold the solution.

  suppose a generic function would refuse to find methods for classes with
  certain properties or relationships (David has already implicated the
  generic functions, btw), such that there would be no danger of calling
  the method that "belongs" to a superclass, would it operationally define
  an interface?  we have method classes, generic function classes, and
  method combination types at our command.  can something be built with
  them that ignors the class precedence list and so does not find methods
  for superclasses of some or any of its arguments?  this does violate the
  spirit of inheritance, but I believe the whole purpose here is to _have_
  "disinherited" interface functions.

  let's do something C++ couldn't do: let's get it right.
  
#:Erik
-- 
  SIGTHTBABW: a signal sent from Unix to its programmers at random
  intervals to make them remember that There Has To Be A Better Way.
From: Harley Davis
Subject: Re: making virtual functions in CL
Date: 
Message-ID: <77umnc$ps9$1@news1-alterdial.uu.net>
Erik sez...
>* ···@sevak.isi.edu (Thomas A. Russ)
>| This is a useful semantic concept when one is defining abstract
>| superclasses, ie, classes which are not expected to be instantiated
>| directly.  This is typically done in order to have a common interface, or
>| in situations where some portion of the functionality can be implemented
>| by methods on the abstract class, but for which some additional concrete
>| methods are required for proper functioning.
>|
>| This does not seem like an unreasonable request.
>
>  no, it isn't: it caused the concept of "interfaces" in Java.  however,
>  the "virtual" _implementation_ of this request as found in C++ is
>  inherently flawed and should not be replicated anywhere.


Actually, Java's interfaces are, IMO, quite flawed because they do not allow
you to define partial implementations of protocols as Russ mentions above.
They only allow you to define the set of method names and argument types for
a particular protocol.

C++'s abstract base classes are much more flexible as they do allow you to
define an appropriate mix of pure interface specifications (pure virtual
functions) and implementations.

Common Lisp is pretty good for this but has no way to specify just
interfaces with no implementation whatsoever - you need to explicitly raise
a runtime error in methods which you want to specify in a superclass but
implement only in a subclass.  Similarly, there is no way to statically
specify abstract classes and it is kind of a pain to even signal the right
error for instantiating supposedly abstract classes.  This may delay the
programmer in finding incomplete concrete class definitions but follows the
generally dynamic and late-binding nature of the language, and has about the
same ramifications as runtime type checking.

I am not clear as to why Erik feels that C++ is especially flawed for this,
other than that its syntax is screwy as usual (no keywords for abstract
classes; need to define a pure virtual to make a base class abstract; pure
virtual function definition syntax is silly.)  There is a reasonable
argument that C++ simply lets you specify too much or requires you to
overdesign your class hierarchies to take advantage of all the static
declarations you can make, but I'm not sure if this is what Erik is getting
at.

BTW, I have played around in Lisp with various ways to define abstract
protocols declaratively rather than dynamically.  I think it is fairly easy
to find a solution using the MOP and some additional macros/keywords as Erik
suggests.  But it's not very easy getting the compiler to check the result
as in C++ and Java.  (FYI, in C++ and Java the compiler will not normally
let you instantiate an abstract class.)

-- Harley
From: Erik Naggum
Subject: Re: making virtual functions in CL
Date: 
Message-ID: <3125665298427378@naggum.no>
* "Harley Davis" <··············@spamless_ilog.com>
| I am not clear as to why Erik feels that C++ is especially flawed for
| this, other than that its syntax is screwy as usual (no keywords for
| abstract classes; need to define a pure virtual to make a base class
| abstract; pure virtual function definition syntax is silly.)  There is a
| reasonable argument that C++ simply lets you specify too much or requires
| you to overdesign your class hierarchies to take advantage of all the
| static declarations you can make, but I'm not sure if this is what Erik
| is getting at.

  the problem with C++ is that it pretends to give you something, but fails
  to follow up on it and actually deliver it.  (this is not unlike most C++
  projects, but I digress.)  in this case, a pure virtual function is a
  good idea that never got anywhere.  it tries to answer the desire for a
  protocol between class designer and subclass implementor, but only the
  first subclass needs to implement it, yet if that one forgets it, some
  subclass of that class might need to, and despite all the "statically
  typed" nonsense, it doesn't really enforce any of this protocol.  it's
  worse to pretend you give somebody something valuable than not to give it.

| BTW, I have played around in Lisp with various ways to define abstract
| protocols declaratively rather than dynamically.  I think it is fairly
| easy to find a solution using the MOP and some additional macros/keywords
| as Erik suggests.  But it's not very easy getting the compiler to check
| the result as in C++ and Java.  (FYI, in C++ and Java the compiler will
| not normally let you instantiate an abstract class.)

  sure, but that's the only bonus you get, and it isn't the one you want,
  which is a way to make sure subclasses that change something that the
  virtual function needs will also supply an implementation of that
  function.  this is actually fairly tricky stuff.  C++ has taken the easy
  way out and did something that looks good to people who don't care to
  think too much about what they get.  stuff like that really bugs me.

#:Erik
-- 
  SIGTHTBABW: a signal sent from Unix to its programmers at random
  intervals to make them remember that There Has To Be A Better Way.
From: Barry Margolin
Subject: Re: making virtual functions in CL
Date: 
Message-ID: <9yJo2.302$oD6.26447@burlma1-snr1.gtei.net>
In article <················@naggum.no>, Erik Naggum  <····@naggum.no> wrote:
>  the problem with C++ is that it pretends to give you something, but fails
>  to follow up on it and actually deliver it.  (this is not unlike most C++
>  projects, but I digress.)  in this case, a pure virtual function is a
>  good idea that never got anywhere.  it tries to answer the desire for a
>  protocol between class designer and subclass implementor, but only the
>  first subclass needs to implement it, yet if that one forgets it, some
>  subclass of that class might need to, and despite all the "statically
>  typed" nonsense, it doesn't really enforce any of this protocol.  it's
>  worse to pretend you give somebody something valuable than not to give it.

This is similar to Kent's point that it's not good enough just to provide
an implementation of a name -- that doesn't guarantee that it actually
implements the protocol.

Unfortunately, there's only so much that you can expect from static
checking like this.  It's not much different from what type checking gets
you -- they can tell you whether the program is "well formed" in some
respects, but not whether it's "correct".  E.g., declaring a function named
"add1" to take and return an integer doesn't prevent it from subtracting
rather than adding.

Some languages allow you to attach preconditions and postconditions to
statements and functions, to try to capture more of the requirements of a
protocol.  Some of these things may be statically checkable.  AFAIK, this
type of stuff is still mostly in research languages, it hasn't reached the
mainstream much.  And it's not clear to me how useful they really are;
considering my above "add1" example, how many programmers would really
write the postcondition after every call to it that the result is 1 more
than the original value?  But I suppose they can be useful on a coarse
scale (I've never actually used such a language, so I don't really know
what it's like).

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Don't bother cc'ing followups to me.
From: Pierre Mai
Subject: Re: making virtual functions in CL
Date: 
Message-ID: <87zp7fxj0t.fsf@orion.dent.isdn.cs.tu-berlin.de>
Barry Margolin <······@bbnplanet.com> writes:

> Some languages allow you to attach preconditions and postconditions to
> statements and functions, to try to capture more of the requirements of a
> protocol.  Some of these things may be statically checkable.  AFAIK, this
> type of stuff is still mostly in research languages, it hasn't reached the
> mainstream much.  And it's not clear to me how useful they really are;

Well, the simple pre- and post-condition type of language has already
"hit the mainstream", as in Bertrand Meyer's Eiffel.  Matthias Hoelzl
has even developed a prototypical implementation of
"Design-By-Contract" for CLOS[1].

> considering my above "add1" example, how many programmers would really
> write the postcondition after every call to it that the result is 1 more
> than the original value?  But I suppose they can be useful on a coarse
> scale (I've never actually used such a language, so I don't really know
> what it's like).

Well, the post-condition would of course be attached to the add1
function, such that the pre- and post-conditions are checked
automatically on every invocation of add1 (otherwise this kind of
thing would be less useful than it actually is).  Indeed Eiffel and
the implementation of DBC in CLOS offer some convenience features,
like class-invariants, which are checked as pre- and post-conditions
on all method invocations for any object of a given class.

But on the whole DBC doesn't address the protocol-definition problem
we where talking about, since it has no real meta-level, that allows
you to talk about the methods/functions belonging to a protocol, their 
interrelation, etc.

I think that this kind of protocol definition could be added to Common 
Lisp with less problems than to languages in the "static-only" camp,
since in CL one isn't restricted to static checking, and one has much
better access to the meta-level that is needed in formulating many of
the more relevant conditions.

Given a facility that allows one to define fairly expressive
conditions on the structure and/or behaviour of a system, one could
define a function like the COMPILE-FLAVOR-METHODS Kent mentioned
(probably better named), which could be invoked after the system was
loaded (and/or periodically thereafter, e.g. when new sub-systems are
loaded, the running system is modified, or just to check that
everything is still in order) to check most of the "statically"
resolvable conditions.  Those conditions which can only be checked at
"run-time", would be checked at run-time, like in Hölzl's DBC.

I think that this kind of functionality is easily implemented in CL,
but is not that simple to design right, since the kind of properties
that should be checkable would probably vary from system to system and 
programmer to programmer...  OTOH I think that MOPs/Aspect-Oriented
Programming should cover some of this territory quite well, and I'd be 
surprised, if there weren't clever research in this area to be
consulted...[2]

Regs, Pierre.

Footnotes: 
[1]  Which goes to show that with CL it isn't necessary to invent a
new language for every kind of methodology one currently is obsessed
with ;->

[2]  In effect, many of the problems of correctness checking of
protocols and their implementations are similar to the kind of
property assertions that are necessary for most OO optimizations.  In
this context, MOPs have been researched quite well, IIRC.

-- 
Pierre Mai <····@acm.org>               http://home.pages.de/~trillian/
  "One smaller motivation which, in part, stems from altruism is Microsoft-
   bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
From: Barry Margolin
Subject: Re: making virtual functions in CL
Date: 
Message-ID: <3p6p2.367$oD6.30292@burlma1-snr1.gtei.net>
In article <··············@orion.dent.isdn.cs.tu-berlin.de>,
Pierre Mai  <····@acm.org> wrote:
>Barry Margolin <······@bbnplanet.com> writes:
>
>> Some languages allow you to attach preconditions and postconditions to
>> statements and functions, to try to capture more of the requirements of a
>> protocol.  Some of these things may be statically checkable.  AFAIK, this
>> type of stuff is still mostly in research languages, it hasn't reached the
>> mainstream much.  And it's not clear to me how useful they really are;
>
>Well, the simple pre- and post-condition type of language has already
>"hit the mainstream", as in Bertrand Meyer's Eiffel.  Matthias Hoelzl
>has even developed a prototypical implementation of
>"Design-By-Contract" for CLOS[1].

I carefully said "mostly", precisely because I suspected there were a small
number of languages like that, but which I didn't know offhand (I've heard
of Eiffel, but don't know much about it).

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Don't bother cc'ing followups to me.
From: Harley Davis
Subject: Re: making virtual functions in CL
Date: 
Message-ID: <783bkm$904$1@news1-alterdial.uu.net>
Erik Naggum wrote in message <················@naggum.no>...
>* "Harley Davis" <··············@spamless_ilog.com>
>| I am not clear as to why Erik feels that C++ is especially flawed for
>| this, other than that its syntax is screwy as usual (no keywords for
>| abstract classes; need to define a pure virtual to make a base class
>| abstract; pure virtual function definition syntax is silly.)  There is a
>| reasonable argument that C++ simply lets you specify too much or requires
>| you to overdesign your class hierarchies to take advantage of all the
>| static declarations you can make, but I'm not sure if this is what Erik
>| is getting at.
>
>  the problem with C++ is that it pretends to give you something, but fails
>  to follow up on it and actually deliver it.  (this is not unlike most C++
>  projects, but I digress.)  in this case, a pure virtual function is a
>  good idea that never got anywhere.  it tries to answer the desire for a
>  protocol between class designer and subclass implementor, but only the
>  first subclass needs to implement it, yet if that one forgets it, some
>  subclass of that class might need to, and despite all the "statically
>  typed" nonsense, it doesn't really enforce any of this protocol.  it's
>  worse to pretend you give somebody something valuable than not to give
it.


Well, the alternatives are basically:

1. Do nothing to support abstract classes and interfaces. (CLOS)
2. Provide limited support at a very superficial level. (C++/Java)
3. Provide full support with arbitrarily complex
spec/implementation/semantics/limitations. (No language known to me.)

If there were at least good working research examples of option 3, it might
make sense to design new languages incorporating this feature - certainly we
all seem to agree that the concept is a good one.  But there are none that
I'm aware of, so realistically only options 1 and 2 are available.  The
question is really whether partial support of protocol definition is better
than no support at all.

I believe partial support is better, if only because it is still useful for
some level of consistency checking and writing a bunch of methods signalling
errors is a pain and does not state the desired semantics as clearly as a
special syntax for abstract classes.

I'm not sure that C++ promises more than it delivers - the language spec
says what the forms in question do, and a brief look at the literature does
not reveal extravagant claims about this feature other than that it allows
the programmer to specify abstract classes that are checked by the compiler
at instantiation time - perhaps not equal to the coming of the messiah as a
feature but still moderately useful.

However, I did find this little tidbit in "The Design and Evolution of C++"
by Stroustrup [p. 261]:

"The combination of abstract classes and virtual base classes was intended
to support a style of programming roughly corresponding to the mixin style
used in some Lisp systems.  That is, an abstract base class defines an
interface, and several derived classes contribute to the implementation.
Each derived class (each mixin) contributes something to the complete class
(mix)."

(I think Stroustrup confused "derived class" with "virtual base class" in
the last two sentences; otherwise I can't make sense of his explanation.)

A more elaborate explanation can be found in the same book on pages 277-279,
where the major claims are that C++'s abstract classes support "a style of
design based on separating the specification of interfaces and
implementation."

Whether the claims for this feature are overblown depends, I suppose, on
your expectations going in; certainly nothing in the book says that C++ can
really do more than it does.  So I would not accept without further evidence
that C++ promises something more valuable than it delivers.

To put all this in perspective, I don't think this one fairly small feature
in C++ does anything close to compensate for all its other flaws and
annoyances as a systems programming language, but I do think there is a
tendency to somewhat overstate the negative claims about the language among
Lispers.

BTW, I don't recall anyone mentioning in this discussion what I consider to
be the one huge advantage that Lisp-based object systems have over most
statically typed OO languages:  The ability to define new methods and
generic functions outside of the scope of a class definition.  There's
little I find more annoying in C++ and Java than having to define all of a
class's methods in the class definition, and nothing more annoying than when
I want to add some new protocol to a class I didn't write.

-- Harley
From: Barry Margolin
Subject: Re: making virtual functions in CL
Date: 
Message-ID: <Ssnp2.377$oD6.33697@burlma1-snr1.gtei.net>
In article <············@news1-alterdial.uu.net>,
Harley Davis <··············@spamless_ilog.com> wrote:
>BTW, I don't recall anyone mentioning in this discussion what I consider to
>be the one huge advantage that Lisp-based object systems have over most
>statically typed OO languages:  The ability to define new methods and
>generic functions outside of the scope of a class definition.  There's
>little I find more annoying in C++ and Java than having to define all of a
>class's methods in the class definition, and nothing more annoying than when
>I want to add some new protocol to a class I didn't write.

There are many in the OO community who feel that these needs imply poor
design.  The goal of information hiding doesn't mesh well with allowing
someone other than the class designer/implementor to define methods.  The
theory is that he should be able to change the implementation of the class
without affecting any outside code (whether this includes subclasses varies
-- C++ has the "protected" designation for members that are visible to
immediate subclasses), so long as it continues to implement the same
protocol via the public interfaces.

To me, such attitudes seem consistent with those folks' preference for B&D
languages with lots of static type declarations, and there are times when
this philosophy is appropriate (large shops with hundreds of "coders"
implementing modules designed by a few "analysts").  Lisp is appropriate
for different circumstances, where the programmers are the designers, and
can take advantage of the freedom it provides (exploratory programming,
rapid prototyping).  If you don't trust your programmers not to hang
themselves if you give them rope, you don't let them use Lisp.

On the other hand, C/C++ give them different pieces of rope.  I find it
hard to believe that you don't trust to pass appropriate data types without
compile-time type checking, but you expect that same programmer to do
memory management properly.  Lisp leaves the hard stuff (memory management)
to the implementation, while easy stuff like type checking is left for the
programmer to do if necessary.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Don't bother cc'ing followups to me.
From: Kent M Pitman
Subject: Re: making virtual functions in CL
Date: 
Message-ID: <sfw90f1hm5t.fsf@world.std.com>
···@sevak.isi.edu (Thomas A. Russ) writes:

> At the risk of doing battle with the redoubtable Erik Naggum, I will
> weigh in here.
 
Hi there.  Glad to see you chime in.  Mind if an alternate battler
steps in, just to keep things lively? :-)

> The original request from David Bakhash seems to be reasonable.  He
> wants to define a class and impose a restriction that all subclasses
> must implement a given method 

I agree this is a reasonable goal.

> in order to fulfill the interface contract
> for the class -- but where there is no general method for the
> superclass.

I think this focuses on where I have a quibble.  As a matter of
personal belief, if nothing else, I think it's fine to want all
subclasses to implement a given method, but its quite a leap to say
that because they have implemented it, they have satisfied an inteface
contract.  It's sort of like saying that writing a yellow sticky note
saying "remember to fill out tax forms" is going to assure I've done
my taxes correctly.  A reminder is a good thing for forgetful people,
but it is a far sight short of a proof that a correct impementation
has occurred.  It might keep me from forgetting to send my tax forms,
but it won't detect the difference between needing to fill out a
Schedule C or not.  I might have a method for filling out taxes that
is wrong, and no amount of reminders to fill out my taxes will
substitute for a knowledge of how to correctly fill them out.
So I am not arguing against wanting the reminders, but I'm saying
it's just a device and not something that really adds fundamental
power to the language nor is it something that if absent leaves the
language fundamentally crippled.

It's more analogous to things like WHEN and UNLESS that make the
language more useful and less error-prone but that don't semantically
extend IF in a real way.  I complain when WHEN and UNLESS are absent
in other languages and dialects because I think it's a difference that
matters, but I don't think the -reason- it matters is one of assuring
correctness, except in the very limited sense that anything that
statistically makes idiosyncratic, error-prone humans a little more
comfortable has a corresponding statistical improvement in program
maintainability.  Quite a noble goal, and for this I support the idea
of catering to such odd preferences people have.  But not because 
it "fulfills an interface contract".

Well, of course, one can write a contract about anything at all.  One
-can-, and often does, write a contract with one employees that asks
them to appear at a certain time for work.  (For some, like cashiers
in a store who have to serve people who arrive at the same time, this
make some sense.  But assume I mean some like programmers whose
project isn't due on the day in question.)  The requirement is
intended to assure that the employee is working, but the requirement
really doesn't measure that the employee is working; more, it
redefines what it is to -be- working.  The measure of whether someone
is present in physical space becomes the measure of whether a company
is moving along, and then there is great surprise when later something
isn't done.  It would have been better to measure progress on goals, 
but that's hard to do--so we substitute something simpler.  And, 
threading up the analogy now, it would be better to measure whether
a program was really "getting filled in".  But we don't always know
when that is.  So we invent ways to slap someone's wrist when they
make a superficial violation of protocol.  And we hope that's enough
to put the fear of God (or fear of Compiler Warnings, as the case
may be) in them, and that the rest will "just happen".

> (The proper term in C++ is PURE virtual function)

This isn't my area of expertise, but sounds more right.

> This is a useful semantic concept when one is defining abstract
> superclasses, ie, classes which are not expected to be instantiated
> directly.  This is typically done in order to have a common interface,
> or in situations where some portion of the functionality can be
> implemented by methods on the abstract class, but for which some
> additional concrete methods are required for proper functioning.

Yes, although it does not detect that perhaps additional concrete 
methods are needed when additional subclassing has occurred.  Neither
does it detect whether the user put the right text in the required
methods.
 
> This does not seem like an unreasonable request.

Answered above. 

> In CLOS, the best that you can do is define a method on the class which
> signals an error, but this forces you to discover the problem at run
> time rather than at compile time.  A notion of an abstract class with
> required methods might be a nice extension to the Common Lisp standard.

To the extent that it's useful to notice this at all, I agree with you
that Common Lisp is deficient for not having a way to notice it early.
I guess what I wish,though, is that CL had a more general mechanism
for noticing that the class was "as complete as it was going to get
and about to be compiled" and for "allowing arbitrary programs to be
run to do arbitrary tests, perhaps not all just syntactic".  The MOP
offers some of that, but perhaps not as much as should be needed... CL
needs a more elaborated sense of things like "class sealing" (in the
Dylan sense) that announce that parts of the construction of a
distributed/modular system are all in place and that it's time for an
aggressive checking and optimziation of whatever needs to be checked
and optimized.  Absent such a language-level declaration, the MOP has
no time to trigger because it has to worry that more changes will happen
later and that an error will be premature.

> As an aside, this is something which has been present in some Lisp
> systems (although not in Common Lisp).  Symbolic's Flavors had a class
> option called required-methods which listed methods that all subclasses
> had to implement in order to be conforming.

Yes.  And I think there was also a (compile-flavor-methods foo) that
you put in your system stuff at the end of the build to say "you've
seen the whole system now--this would be a good time to check that
kind of stuff.  Because absent that, I think you had to wait until
MAKE-INSTANCE time to find out that required methods were not present,
since otherwise you had no way of telling that the method wasn't still
in another file yet to be loaded.  For what it's worth, my notes say
that Gregor Kiczales (MOP author) had agreed by Mar 91 that something
like this was needed, but that we had no spcific proposal and it fell
through the cracks.  (My notes after the absence of a specific
proposal say "Still no proposal.  Sigh... users are not gonna like
this.")  So later, in my Public Review comments on the draft
specification, I proposed adding something equvialent to
compile-flavor-methods for CL that either took a method name or a
class name or a method signature and forced compilation/checking of
the appropriate methods.  But the committee opted not to act on this
either.  Ah well.  I didn't really expect them to.  I just wanted to
be on record as having known this was an issue of importance so that
when fingers started getting pointed, I wasn't among those who was
pointed at.  So don't take any of my above remarks as saying we
shouldn't have the feature being discussed--I'm just talking about
the philosophical underpinnings of the want.
From: Paul Rudin
Subject: Re: making virtual functions in CL
Date: 
Message-ID: <m3yamy8b8h.fsf@shodan.demon.co.uk>
···@sevak.isi.edu (Thomas A. Russ) writes:


> 
> This is a useful semantic concept when one is defining abstract
> superclasses, ie, classes which are not expected to be instantiated
> directly.  This is typically done in order to have a common interface,
> or in situations where some portion of the functionality can be
> implemented by methods on the abstract class, but for which some
> additional concrete methods are required for proper functioning.
> 
> This does not seem like an unreasonable request.
> 

Is there a reason why this couldn't be implemented using a
non-standard metaclass for the classes for which this behaviour might
be desirable? (Apart, of course, from the work involved.)
From: Paul Rudin
Subject: Re: making virtual functions in CL
Date: 
Message-ID: <m3yamp0x5v.fsf@shodan.demon.co.uk>
Paul Rudin <·····@shodan.demon.co.uk> writes:

> ···@sevak.isi.edu (Thomas A. Russ) writes:
> 
> 
> > 
> > This is a useful semantic concept when one is defining abstract
> > superclasses, ie, classes which are not expected to be instantiated
> > directly.  This is typically done in order to have a common interface,
> > or in situations where some portion of the functionality can be
> > implemented by methods on the abstract class, but for which some
> > additional concrete methods are required for proper functioning.
> > 
> > This does not seem like an unreasonable request.
> > 
> 
> Is there a reason why this couldn't be implemented using a
> non-standard metaclass for the classes for which this behaviour might
> be desirable? (Apart, of course, from the work involved.)

And thinking about it, this probably isn't much work involved. All
that's required would be a new metaclass based on standard-class with
one additionional slot to tell you whether or not it's virtual, and a
new before method on MAKE-INSTANCE specialised to this class that
complains when you try and make an instance if this slot is non-nil.
(+ a bit of syntactic sugar here and there...)
From: ········@my-dejanews.com
Subject: Re: making virtual functions in CL
Date: 
Message-ID: <78nl61$c7t$1@nnrp1.dejanews.com>
In article <··············@shodan.demon.co.uk>,
  Paul Rudin <·····@shodan.demon.co.uk> wrote:
> > ···@sevak.isi.edu (Thomas A. Russ) writes:
> > Is there a reason why this couldn't be implemented using a
> > non-standard metaclass for the classes for which this behaviour might
> > be desirable? (Apart, of course, from the work involved.)
>
> And thinking about it, this probably isn't much work involved. All
> that's required would be a new metaclass based on standard-class with
> one additionional slot to tell you whether or not it's virtual, and a
> new before method on MAKE-INSTANCE specialised to this class that
> complains when you try and make an instance if this slot is non-nil.
> (+ a bit of syntactic sugar here and there...)

This is essentially the approach we have taken.

A new class option :ABSTRACT may be specified. It defaults to nil but I find
it useful documentation to specify :ABSTRACT nil even though it is not
required.

We define a primary method on ALLOCATE-INSTANCE which errors when an attempt
is made to instantiate an abstract class.

I also use the accessor ABSTRACT in some cases e.g. when collecting a list of
slots in a class hierarchy there are some occassions when I want to filter out
slots belonging to abstract classes.

Mark

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own