From: Ari Johnson
Subject: CLOS Properties Question
Date: 
Message-ID: <Oijoc.114381$Jy3.63915@fed1read03>
A nifty feature of Ruby and C# is property getter/setter methods.  This 
lets you do, for example, the following:

--C# code--
class root {
   protected string _name;
   public string name {
     get { return _name; }
     set { _name = name; }
   }
};

class leaf : root {
   private bool valid_name(string name) {
     return false;
   }
   new public string name {
     get { return _name; }
     set { if(valid_name(name)) _name = name; }
   }
};
-----------

The specific feature I'm looking at is the property setter for name in 
the leaf class.  Does CLOS offer this functionality?  When I do the 
following, I want to be able to redefine the setter for the name slot in 
leaf.  Can this be done?  What's considered the best way?

--Lisp Code--
(defclass root ()
   ((name :accessor name :initarg :name)))
(defclass leaf (root) ())
-------------

For a simple example, let's say I want the following to occur:

* (setf a-root (make-instance 'root :name "The Root"))
#<ROOT ...>
* (setf a-leaf (make-instance 'leaf :name "The Leaf"))
#<LEAF ...>
* (setf (name a-root) "A Root")
"A Root"
* (valid-name "Bob")
NIL
* (valid-name "A Leaf")
T
* (setf (name a-leaf) "Bob")
NIL
* (name a-leaf)
"The Leaf"
* (setf (name a-leaf) "A Leaf")
"A Leaf"
* (name a-leaf)
"A Leaf"

Does this make sense?  How can it be done?  Thanks!

From: Christophe Rhodes
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <sq4qqmqhhr.fsf@lambda.dyndns.org>
Ari Johnson <·····@hotmail.com> writes:

> Does this make sense?  How can it be done?  Thanks!

Not to me.  You gave a fair amount of examples, but without ever
really _saying_ what behaviour you wanted -- trying to
reverse-engineer your request is a bit like reverse-engineering
'painting by numbers' :-)

If I had to guess, I would say
  (defclass root () ((name :initarg :name :accessor name)))
  (defclass leaf (root) ())
  (defmethod (setf name) :around (name (leaf leaf))
    (when (valid-name name)
      (call-next-method)))
would give you the functionality you ask for, but if I'm wrong, could
you specify what you want in words?

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <FGroc.119618$Jy3.4274@fed1read03>
Christophe Rhodes wrote:
> Ari Johnson <·····@hotmail.com> writes:
> 
> 
>>Does this make sense?  How can it be done?  Thanks!
> 
> 
> Not to me.  You gave a fair amount of examples, but without ever
> really _saying_ what behaviour you wanted -- trying to
> reverse-engineer your request is a bit like reverse-engineering
> 'painting by numbers' :-)

"A nifty feature ... is property getter/setter methods.  <example>"
"The specific feature I'm looking at is the property setter ...  When I 
do the following, I want to be able to redefine the setter for the name 
slot in leaf."
"For a simple example, let's say I want the following to occur: <REPL 
interaction>"

I'd say I was clear enough.  Regardless:

> If I had to guess, I would say
>   (defclass root () ((name :initarg :name :accessor name)))
>   (defclass leaf (root) ())
>   (defmethod (setf name) :around (name (leaf leaf))
>     (when (valid-name name)
>       (call-next-method)))
> would give you the functionality you ask for, but if I'm wrong, could
> you specify what you want in words?

Whether by osmosis or a better understanding than you let on in your 
first paragraph, I believe you guessed correctly. :)

As I'm new to CLOS, I don't have a thorough grasp on :around methods and 
their ilk, but your code looks to do what I want it to.  Thanks.
From: Marco Gidde
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <lzpt99cply.fsf@tristan.br-automation.de>
Christophe Rhodes <·····@cam.ac.uk> writes:

> If I had to guess, I would say
>   (defclass root () ((name :initarg :name :accessor name)))
>   (defclass leaf (root) ())
>   (defmethod (setf name) :around (name (leaf leaf))
>     (when (valid-name name)
>       (call-next-method)))

A similar snippet was posted by someone else and I ask myself, why the
:around is necessary since (setf name) is not specialized for an
argument of type leaf. Or is this method implicitly defined by
DEFCLASS when leaf is derived from root? Or is it just a question of
style?


Marco
From: Christophe Rhodes
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <sqwu3hs1uv.fsf@lambda.dyndns.org>
Marco Gidde <···········@tiscali.de> writes:

> Christophe Rhodes <·····@cam.ac.uk> writes:
>
>> If I had to guess, I would say
>>   (defclass root () ((name :initarg :name :accessor name)))
>>   (defclass leaf (root) ())
>>   (defmethod (setf name) :around (name (leaf leaf))
>>     (when (valid-name name)
>>       (call-next-method)))
>
> A similar snippet was posted by someone else and I ask myself, why the
> :around is necessary since (setf name) is not specialized for an
> argument of type leaf. 

It's :around because conceptually that's what :around methods do, I
think.  It's not a primary method because the LEAF class could easily
be redefined to be
  (defclass leaf (root) ((name :accessor name :accessor leaf-name)))
which would define (maybe later) a (SETF NAME) method.

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: Joe Marshall
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <isf0tp0b.fsf@ccs.neu.edu>
Marco Gidde <···········@tiscali.de> writes:

> Christophe Rhodes <·····@cam.ac.uk> writes:
>
>> If I had to guess, I would say
>>   (defclass root () ((name :initarg :name :accessor name)))
>>   (defclass leaf (root) ())
>>   (defmethod (setf name) :around (name (leaf leaf))
>>     (when (valid-name name)
>>       (call-next-method)))
>
> A similar snippet was posted by someone else and I ask myself, why the
> :around is necessary since (setf name) is not specialized for an
> argument of type leaf. Or is this method implicitly defined by
> DEFCLASS when leaf is derived from root? Or is it just a question of
> style?

I don't think you want an :around method here.  If you subclass LEAF
you don't want this method to run before the subclass methods which
may change the name.
From: Marco Antoniotti
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <F3roc.197$a5.56126@typhoon.nyu.edu>
Ari Johnson wrote:

> A nifty feature of Ruby and C# is property getter/setter methods.  This 
> lets you do, for example, the following:
> 
> --C# code--
> class root {
>   protected string _name;
>   public string name {
>     get { return _name; }
>     set { _name = name; }
>   }
> };
> 
> class leaf : root {
>   private bool valid_name(string name) {
>     return false;
>   }
>   new public string name {
>     get { return _name; }
>     set { if(valid_name(name)) _name = name; }
>   }
> };
> -----------
> 
> The specific feature I'm looking at is the property setter for name in 
> the leaf class.  Does CLOS offer this functionality?

This question is obviously better rephrased as "what functionality of 
CLOS am I missing in C#, C++, Java and SLDJ (Scripting Language Du Jour)"?




   When I do the
> following, I want to be able to redefine the setter for the name slot in 
> leaf.  Can this be done?  What's considered the best way?
> 
> --Lisp Code--
> (defclass root ()
>   ((name :accessor name :initarg :name)))
> (defclass leaf (root) ())
> -------------
> 
> For a simple example, let's say I want the following to occur:
> 
> * (setf a-root (make-instance 'root :name "The Root"))
> #<ROOT ...>
> * (setf a-leaf (make-instance 'leaf :name "The Leaf"))
> #<LEAF ...>
> * (setf (name a-root) "A Root")
> "A Root"
> * (valid-name "Bob")
> NIL
> * (valid-name "A Leaf")
> T
> * (setf (name a-leaf) "Bob")
> NIL
> * (name a-leaf)
> "The Leaf"
> * (setf (name a-leaf) "A Leaf")
> "A Leaf"
> * (name a-leaf)
> "A Leaf"
> 
> Does this make sense?  How can it be done?  Thanks!


(defclass root ()
   ((name :accessor name :initarg :name)))

(defclass leaf (root)
   ())

(defmethod valid-name-p ((l leaf)) nil)

(defmethod (setf name) :around (n (l leaf))
    (when (valid-name-p n) (call-next-method)))

This is what you wanted.  You can vary this theme.

However:

1 - encapsulation in CL is achieved through packages.
2 - I bet that, given the kind of question you asked, that you are on
     the way of enlightment by multi methods :)

Cheers
--
Marco
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <70soc.119809$Jy3.46332@fed1read03>
Marco Antoniotti wrote:
> 1 - encapsulation in CL is achieved through packages.

Is this a cry against objects?  Certainly, many languages encourage bad 
judgement as to what should be an object.  I do think that CL's package 
system seems a little subpar regarding how cleanly a package and its 
contents are defined, but I suppose that's necessary to facilitate 
interaction with the REPL (it'd be a lot harder if you had to do 
(in-package "package" (code)) every line).

> 2 - I bet that, given the kind of question you asked, that you are on
>     the way of enlightment by multi methods :)

Already there - I can see the light of the concept, but I can't reach 
the implementation manual yet. :)
From: Marco Antoniotti
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <JRsoc.202$a5.56088@typhoon.nyu.edu>
Ari Johnson wrote:

> Marco Antoniotti wrote:
> 
>> 1 - encapsulation in CL is achieved through packages.
> 
> 
> Is this a cry against objects?

Well.  Not really.  It was just a way to prevent a usual thread like 
"how do you do private and protected in CL".


   Certainly, many languages encourage bad
> judgement as to what should be an object.  I do think that CL's package 
> system seems a little subpar regarding how cleanly a package and its 
> contents are defined, but I suppose that's necessary to facilitate 
> interaction with the REPL (it'd be a lot harder if you had to do 
> (in-package "package" (code)) every line).

The CL package system operates at the file level.  It is true that you 
do not have a "bracketing" form for package content, but that is just 
either a nuisance or a good thing, YMMV.  In any case, IMO the situation 
is not all that different from C++ namespaces or Ada packages.

I'd say it is one of those things that require some discipline, like

#ifndef _MY_MODULE_H
#define _MY_MODULE_H

/* ... */

#endif /* _MY_MODULE_H */

in C.

Cheers
--
Marco
From: Christopher C. Stacy
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <uwu3h1jvt.fsf@news.dtpq.com>
>>>>> On Wed, 12 May 2004 13:07:54 -0400, Marco Antoniotti ("Marco") writes:

 Marco> Ari Johnson wrote:

 >> Marco Antoniotti wrote:
 >> 
 >>> 1 - encapsulation in CL is achieved through packages.
 >> Is this a cry against objects?

 Marco> Well.  Not really.  It was just a way to prevent a usual thread like
 Marco> "how do you do private and protected in CL".


 Marco>    Certainly, many languages encourage bad
 >> judgement as to what should be an object.  I do think that CL's
 >> package system seems a little subpar regarding how cleanly a package
 >> and its contents are defined, but I suppose that's necessary to
 >> facilitate interaction with the REPL (it'd be a lot harder if you
 >> had to do (in-package "package" (code)) every line).

 Marco> The CL package system operates at the file level.  It is true
 Marco> that you do not have a "bracketing" form for package content,
 Marco> but that is just either a nuisance or a good thing, YMMV.

Huh?  The package is normally selected with IN-PACKAGE; it's an
input-stream-level thing, not a file thing.  You can have as many
calls to IN-PACKAGE in a file as you like.  (Most people just have
one, at the top of the file, because otherwise it's confusing for
someone to have to imagine that there might be more hidden down
later and go hunting for them.  But that's just a practice.)

The Common Lisp package system operates at the level of symbols, 
and doesn't have anything to do with files or text.  

I'm not sure what Ari means by "subpar".  Possibly he thinks that
"package" means something different from what we think it means.
A "package" is called a "namespace" in some other languages.
From: Marco Antoniotti
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <mGwoc.1$qp6.91@typhoon.nyu.edu>
Christopher C. Stacy wrote:
>>>>>>On Wed, 12 May 2004 13:07:54 -0400, Marco Antoniotti ("Marco") writes:
> 
> 
>  Marco> Ari Johnson wrote:
> 
>  >> Marco Antoniotti wrote:
>  >> 
>  >>> 1 - encapsulation in CL is achieved through packages.
>  >> Is this a cry against objects?
> 
>  Marco> Well.  Not really.  It was just a way to prevent a usual thread like
>  Marco> "how do you do private and protected in CL".
> 
> 
>  Marco>    Certainly, many languages encourage bad
>  >> judgement as to what should be an object.  I do think that CL's
>  >> package system seems a little subpar regarding how cleanly a package
>  >> and its contents are defined, but I suppose that's necessary to
>  >> facilitate interaction with the REPL (it'd be a lot harder if you
>  >> had to do (in-package "package" (code)) every line).
> 
>  Marco> The CL package system operates at the file level.  It is true
>  Marco> that you do not have a "bracketing" form for package content,
>  Marco> but that is just either a nuisance or a good thing, YMMV.
> 
> Huh?  The package is normally selected with IN-PACKAGE; it's an
> input-stream-level thing, not a file thing.

Well, yes.  I apologize for the unprecision.

   You can have as many
> calls to IN-PACKAGE in a file as you like.

Believe me.  I know.  I was maintaining ILISP for a while and I am sure 
the SLIME folks are having as much fun with this as we did with ILISP. :)

> (Most people just have
> one, at the top of the file, because otherwise it's confusing for
> someone to have to imagine that there might be more hidden down
> later and go hunting for them.  But that's just a practice.)
> 
> The Common Lisp package system operates at the level of symbols, 
> and doesn't have anything to do with files or text.

Yes.  But IN-PACKAGE affects how a file is loaded and is compiled, so 
the package system must be put in relation to files and, as you note, 
streams, at one level or another.

> I'm not sure what Ari means by "subpar".  Possibly he thinks that
> "package" means something different from what we think it means.
> A "package" is called a "namespace" in some other languages.

I think that at a minimum, the OP refers to the lingustic notion that 
"things that are part of a package"  should be clearly "bracketed", like Ada

package foo is
    -------
end package

One way to somehow map this notion to CL practice is to use files with a 
single IN-PACKAGE at the top as you noted.


Cheers
--
Marco
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <2zzoc.124539$Jy3.84619@fed1read03>
Christopher C. Stacy wrote:
>>>>>>On Wed, 12 May 2004 13:07:54 -0400, Marco Antoniotti ("Marco") writes:
> 
> 
>  Marco> Ari Johnson wrote:
> 
>  >> Marco Antoniotti wrote:
>  >> 
>  >>> 1 - encapsulation in CL is achieved through packages.
>  >> Is this a cry against objects?
> 
>  Marco> Well.  Not really.  It was just a way to prevent a usual thread like
>  Marco> "how do you do private and protected in CL".
> 
> 
>  Marco>    Certainly, many languages encourage bad
>  >> judgement as to what should be an object.  I do think that CL's
>  >> package system seems a little subpar regarding how cleanly a package
>  >> and its contents are defined, but I suppose that's necessary to
>  >> facilitate interaction with the REPL (it'd be a lot harder if you
>  >> had to do (in-package "package" (code)) every line).
> 
>  Marco> The CL package system operates at the file level.  It is true
>  Marco> that you do not have a "bracketing" form for package content,
>  Marco> but that is just either a nuisance or a good thing, YMMV.
> 
> Huh?  The package is normally selected with IN-PACKAGE; it's an
> input-stream-level thing, not a file thing.  You can have as many
> calls to IN-PACKAGE in a file as you like.  (Most people just have
> one, at the top of the file, because otherwise it's confusing for
> someone to have to imagine that there might be more hidden down
> later and go hunting for them.  But that's just a practice.)
> 
> The Common Lisp package system operates at the level of symbols, 
> and doesn't have anything to do with files or text.  
> 
> I'm not sure what Ari means by "subpar".  Possibly he thinks that
> "package" means something different from what we think it means.
> A "package" is called a "namespace" in some other languages.

I didn't mean that the package system itself is subpar, but rather that 
the interface to it is, in the sense that the very level of confusion 
that you mentioned above, and that I originally suggested an explanation 
for that you agree with: it's designed to operate at the input stream 
level, which lets you do silly things like define multiple packages 
within a single file.  I'm not saying that it requires you to do silly 
things, just that it allows you to, so that you can't assume that the 
code you're reading doesn't do them.

Another thing I don't like is having to list all the exported symbols in 
more or less one place.  This makes it harder to tell if a function is 
exported just by looking at the function, making it harder to read code.

Yes, I know it's probably just a Lisp mindset thing, but that doesn't 
make it any less annoying for new converts, and I haven't heard any good 
reasons for it being exactly the way it is (whereas there are good 
reasons for methods being defined separately from classes, for example).

Ari
From: ·········@random-state.net
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <c7uhed$a1a0o$1@midnight.cs.hut.fi>
Ari Johnson <·····@hotmail.com> wrote:

> Another thing I don't like is having to list all the exported symbols in 
> more or less one place.  This makes it harder to tell if a function is 
> exported just by looking at the function, making it harder to read code.

See EXPORT &co. Best used with MAKE-PACKAGE, not DEFPACKAGE.

Cheers,

  -- Nikodemus
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <ChAoc.124605$Jy3.57982@fed1read03>
·········@random-state.net wrote:

> Ari Johnson <·····@hotmail.com> wrote:
> 
> 
>>Another thing I don't like is having to list all the exported symbols in 
>>more or less one place.  This makes it harder to tell if a function is 
>>exported just by looking at the function, making it harder to read code.
> 
> 
> See EXPORT &co. Best used with MAKE-PACKAGE, not DEFPACKAGE.

How does export make it easier to see that (defun f (x)) is exported 
when the related (export '(f)) could be anywhere, even in another file?
From: Adam Warner
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <pan.2004.05.13.03.47.51.768702@consulting.net.nz>
Hi Ari Johnson,

>>>Another thing I don't like is having to list all the exported symbols
>>>in more or less one place.  This makes it harder to tell if a function
>>>is exported just by looking at the function, making it harder to read
>>>code.
>> 
>> 
>> See EXPORT &co. Best used with MAKE-PACKAGE, not DEFPACKAGE.
> 
> How does export make it easier to see that (defun f (x)) is exported
> when the related (export '(f)) could be anywhere, even in another file?

By choosing to place the related exports in sensible places instead of
"anywhere". You have to take responsibility for the code you create.

Here's a sensible example:

(export 'f)
(defun f (x))

(export 'g)
(defun g (x))

Another option would be to define a macro that performs the exporting in
addition to the function definition.

Heed the advice about never using DEFPACKAGE when you are incrementally
exporting from a package. If there is a discrepancy between the symbols
exported from the DEFPACKAGE form and the symbols exported using EXPORT
some compilers will complain and in some build systems compilation may be
aborted by default.

Regards,
Adam
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <RhCoc.125281$Jy3.93445@fed1read03>
Adam Warner wrote:
> Hi Ari Johnson,
> 
> 
>>>>Another thing I don't like is having to list all the exported symbols
>>>>in more or less one place.  This makes it harder to tell if a function
>>>>is exported just by looking at the function, making it harder to read
>>>>code.
>>>
>>>
>>>See EXPORT &co. Best used with MAKE-PACKAGE, not DEFPACKAGE.
>>
>>How does export make it easier to see that (defun f (x)) is exported
>>when the related (export '(f)) could be anywhere, even in another file?
> 
> 
> By choosing to place the related exports in sensible places instead of
> "anywhere". You have to take responsibility for the code you create.

I can't assume that my choices in this regard will be the same choices 
made by other programmers.  Always assume that other people's code will 
be as far away from sensible as the language allows.  That's why Perl is 
write-once/read-never.  With a language as elegant as Lisp, it's 
bothersome to me that something like this allows for as wrong of a use 
as it does.  And you can't go claiming that being able to randomly place 
your exports makes the language more powerful...or can you?  I hope not. :)
From: Pascal Costanza
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <c7v9sc$7r8$1@newsreader2.netcologne.de>
Ari Johnson wrote:

> And you can't go claiming that being able to randomly place 
> your exports makes the language more powerful...or can you?  I hope not. :)

Sure, you can change the stuff that is exported by a package at run time.


Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: Joe Marshall
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <65b0tnu9.fsf@ccs.neu.edu>
Ari Johnson <·····@hotmail.com> writes:

> I can't assume that my choices in this regard will be the same choices
> made by other programmers.  

That is true.

> Always assume that other people's code will be as far away from
> sensible as the language allows.

You should not use code written by people that have no sense.  If the
language forces them to write code that *appears* coherent, it makes
it harder to know if the author is out of his mind.

> That's why Perl is write-once/read-never.  With a language as
> elegant as Lisp, it's bothersome to me that something like this
> allows for as wrong of a use as it does.

Lisp is agnostic about `right' and `wrong' use.  I like it that way
because it allows me to do things that are against conventional
wisdom, but obviously `right'.

> And you can't go claiming that being able to randomly place your
> exports makes the language more powerful...or can you?  I hope
> not. :) 

I can.  But let's not say `randomly'.
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <iOMoc.126227$Jy3.510@fed1read03>
Joe Marshall wrote:

> Ari Johnson <·····@hotmail.com> writes:
> 
> 
>>I can't assume that my choices in this regard will be the same choices
>>made by other programmers.  
> 
> 
> That is true.
> 
> 
>>Always assume that other people's code will be as far away from
>>sensible as the language allows.
> 
> 
> You should not use code written by people that have no sense.  If the
> language forces them to write code that *appears* coherent, it makes
> it harder to know if the author is out of his mind.

There are many who would claim that you can tell immediately that the 
author is out of his mind if the code is written in Lisp.

> 
> 
>>That's why Perl is write-once/read-never.  With a language as
>>elegant as Lisp, it's bothersome to me that something like this
>>allows for as wrong of a use as it does.
> 
> 
> Lisp is agnostic about `right' and `wrong' use.  I like it that way
> because it allows me to do things that are against conventional
> wisdom, but obviously `right'.

I agree, in general, but there are specific things that are easy to do 
'wrong' where the 'wrong' way is really hard to justify as being right. 
  I'd say random dispersion of (export ...)'s throughout your code would 
qualify for this, but if you reorganize your code a bunch and had 
grouped (export ...)'s near the definition of the things a symbol for 
which they export, it's quite possible you'll end up with that scenario.

> 
> 
>>And you can't go claiming that being able to randomly place your
>>exports makes the language more powerful...or can you?  I hope
>>not. :) 
> 
> 
> I can.  But let's not say `randomly'.

Arbitrarily, then?
From: Christopher C. Stacy
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <u1xlokyq8.fsf@news.dtpq.com>
If you're looking for a language that will force you (and other programmers) 
into using only some "right" solution, Lisp is NOT the language for you.
Although Common Lisp has made a set of decisions about how to do certain
things, and some things that are not allowed, the over-arching concept
of Lisp is flexibility.

The situation is analagous to what people sometimes say about C.  
They say that C is a "power tool" that can be abused, but it gives 
you full access and flexibility to the lowest level of the machine.
(For some value of "machine", anyway.)  Lisp is likewise a power tool, 
but it's giving you full access to the highest levels of the machine.
In either case, use of such tools is best left to the engineers and
artists who have a good sense of design and aesthetics, and can
appreciate the full context for a given piece of their work.

If that's not what you want, I would suggest perhaps Java.
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <WW5pc.3067$Yg.1719@fed1read05>
Christopher C. Stacy wrote:

> If you're looking for a language that will force you (and other programmers) 
> into using only some "right" solution, Lisp is NOT the language for you.
> Although Common Lisp has made a set of decisions about how to do certain
> things, and some things that are not allowed, the over-arching concept
> of Lisp is flexibility.

As long as I learn what those decisions were so I can stick to 
convention where it makes sense to, I have no problem with that.

> The situation is analagous to what people sometimes say about C.  
> They say that C is a "power tool" that can be abused, but it gives 
> you full access and flexibility to the lowest level of the machine.
> (For some value of "machine", anyway.)  Lisp is likewise a power tool, 
> but it's giving you full access to the highest levels of the machine.
> In either case, use of such tools is best left to the engineers and
> artists who have a good sense of design and aesthetics, and can
> appreciate the full context for a given piece of their work.

Good analogy.

> If that's not what you want, I would suggest perhaps Java.

Java doesn't enforce doing things a given way much more than C does.  If 
I wanted that as the primary feature, I'd go back to Ada. :P
From: Adam Warner
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <pan.2004.05.13.04.39.26.474330@consulting.net.nz>
Hi Ari Johnson,

>>>How does export make it easier to see that (defun f (x)) is exported
>>>when the related (export '(f)) could be anywhere, even in another file?
>> 
>> 
>> By choosing to place the related exports in sensible places instead of
>> "anywhere". You have to take responsibility for the code you create.
> 
> I can't assume that my choices in this regard will be the same choices
> made by other programmers.  Always assume that other people's code will
> be as far away from sensible as the language allows.

No. There is very often only one acceptable community option even given a
wide range of semantically neutral choices.

I assure you that if I replied with this code example:

(
  export 'f
)

Or this factorial:

(defun fact (n)
  (if (zerop n)
      1
      (* n (fact (1- n)
           )
      )
  )
)

There would be a comment about my perfectly legal parentheses.

There are also conventions like using asterisks in global dynamic variable
names. Oftentimes you will trust that the programmer has followed these
conventions until investigations demonstrates otherwise.

> That's why Perl is write-once/read-never.

I believe you will find Perl was designed as a syntactically compact
language. Common Lisp is an abstractly compact language. Many of the
function and macro names are not compact but Lisp's powerful function and
code generation abstractions support development of large programs that
both become compact and intelligible.

> With a language as elegant as Lisp, it's bothersome to me that something
> like this allows for as wrong of a use as it does.

Until you internalise Lisp it is no surprise that you should be bothered.
For example I used to be bothered about bugs caused by mutating objects
like quoted lists. Now I enjoy the power of choosing to represent data in
immutable and mutable ways.

> And you can't go claiming that being able to randomly place your exports
> makes the language more powerful...or can you?  I hope not. :)

Of course I can. An export just affects access to a symbol. In the
examples we discussed you are not exporting the function f. You are
exporting the symbol f. You just so happen to define the function
namespace of the symbol f somewhere else in your program. It's up to you
to choose to put the symbol export and function definition in a similar
place within your code if you wish to do so.

If you are reviewing others code it is quite likely you will have to
consult the list of exported symbols within a DEFPACKAGE form. There are
also functions you can evaluate to obtain the list of exported symbols
within a package.

Regards,
Adam
From: Alan Shutko
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <87k6zg5uji.fsf@wesley.springies.com>
Ari Johnson <·····@hotmail.com> writes:

> Another thing I don't like is having to list all the exported symbols
> in more or less one place.  This makes it harder to tell if a function
> is exported just by looking at the function, making it harder to read
> code.

If I'm just looking at the function, I hit C-c C-d in SLIME to
describe the symbol, which tells me if it's exported or not.

-- 
Alan Shutko <···@acm.org> - I am the rocks.
"I don't want to be the conscience of anybody." Marlon Brando
From: Joe Marshall
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <ad0ctolo.fsf@ccs.neu.edu>
Ari Johnson <·····@hotmail.com> writes:

> I didn't mean that the package system itself is subpar, but rather
> that the interface to it is, in the sense that the very level of
> confusion that you mentioned above, and that I originally suggested an
> explanation for that you agree with: it's designed to operate at the
> input stream level, which lets you do silly things like define
> multiple packages within a single file.  I'm not saying that it
> requires you to do silly things, just that it allows you to, so that
> you can't assume that the code you're reading doesn't do them.

I dislike the package system, but...

> Another thing I don't like is having to list all the exported symbols
> in more or less one place.  

Why do you think you have to do this?

> This makes it harder to tell if a function
> is exported just by looking at the function, making it harder to read
> code.

(defmacro defun-public (&whole form) `(defun ,@(cdr form)))
(defmacro defun-private (&whole form) `(defun ,@(cdr form)))

Now you can tell just by looking at the code.  Note that these macros
don't *do* anything, but that's on purpose.  If you want to ignore the
annotation and call a `private' function, go ahead.
From: Fred Gilham
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <u7sme4cq3d.fsf@snapdragon.csl.sri.com>
Joe Marshall <···@ccs.neu.edu> wrote:
> (defmacro defun-public (&whole form) `(defun ,@(cdr form)))
> (defmacro defun-private (&whole form) `(defun ,@(cdr form)))

I suppose you could even make defun-public export the symbol.

This whole discussion reminds me of a scene from THE SHAWSHANK
REDEMPTION.  After Morgan Freeman's character (Red) gets out of jail,
he gets a job bagging groceries.  When he has to use the bathroom, he
yells out, "Bathroom break, boss?"  The boss pulls him over and says
that he doesn't have to ask if he wants to use the bathroom.

There's this concept in the movie of becoming "institutionalized",
that is, unable to survive outside of the structure of the prison.

Perhaps C++ programmers are institutionalized.  Here's a quote from
the movie:

     These walls are kind of funny.  First you hate 'em, then you get
     used to 'em.  Enough time passes, gets so you depend on them.
     That's institutionalized.  They send you here for life, that's
     exactly what they take.  The part that counts, anyways.

In Lisp, you don't have to ask the compiler for permission to take a
leak. :-)

-- 
Fred Gilham                                         ······@csl.sri.com
In the course of making code more readable, performance was
accidentally improved by about 20%. --- From BRL 2.1.23 release notes
From: Gareth McCaughan
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <871xln7srg.fsf@g.mccaughan.ntlworld.com>
Fred Gilham wrote:

> In Lisp, you don't have to ask the compiler for permission to take a
> leak. :-)

I thought the GC was supposed to prevent those.

-- 
Gareth McCaughan
.sig under construc
From: Thomas F. Burdick
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <xcv1xlnxuk6.fsf@famine.OCF.Berkeley.EDU>
Gareth McCaughan <················@pobox.com> writes:

> Fred Gilham wrote:
> 
> > In Lisp, you don't have to ask the compiler for permission to take a
> > leak. :-)
> 
> I thought the GC was supposed to prevent those.

Nah mayn, it cleans up after you.  It's like the difference between
the subway here and in NYC -- in NYC, they understand you might let it
go anywhere ... C++ has SF's carpeted trains.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <SKMoc.126226$Jy3.103553@fed1read03>
Joe Marshall wrote:

> Ari Johnson <·····@hotmail.com> writes:
> 
> 
>>I didn't mean that the package system itself is subpar, but rather
>>that the interface to it is, in the sense that the very level of
>>confusion that you mentioned above, and that I originally suggested an
>>explanation for that you agree with: it's designed to operate at the
>>input stream level, which lets you do silly things like define
>>multiple packages within a single file.  I'm not saying that it
>>requires you to do silly things, just that it allows you to, so that
>>you can't assume that the code you're reading doesn't do them.
> 
> 
> I dislike the package system, but...
> 
> 
>>Another thing I don't like is having to list all the exported symbols
>>in more or less one place.  
> 
> 
> Why do you think you have to do this?
> 
> 
>>This makes it harder to tell if a function
>>is exported just by looking at the function, making it harder to read
>>code.
> 
> 
> (defmacro defun-public (&whole form) `(defun ,@(cdr form)))
> (defmacro defun-private (&whole form) `(defun ,@(cdr form)))
> 
> Now you can tell just by looking at the code.  Note that these macros
> don't *do* anything, but that's on purpose.  If you want to ignore the
> annotation and call a `private' function, go ahead.

Your final statement holds even if defun-public does an `(export ,(car 
form)), while actually accomplishing what I wanted.  The problem is that 
using silly C++ compatibility macros isn't a good solution, especially 
how far away from comprehensive it is.  I suspect that there is no good 
solution, and that's why it's left the way it is.
From: Tim Bradshaw
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <fbc0f5d1.0405130929.74407df9@posting.google.com>
Ari Johnson <·····@hotmail.com> wrote in message news:<······················@fed1read03>...

> Another thing I don't like is having to list all the exported symbols in 
> more or less one place.  This makes it harder to tell if a function is 
> exported just by looking at the function, making it harder to read code.
> 

Well, I write a lot of python at the moment, and it's *horrible*
having to remember that all your unexported names should be _*, or
forgetting that and exporting stuff you didn't mean to.  I *really
like* something at the start of a module which says `these are the
names this thing exports'.

If you want this kind of thing in CL it's fairly easy to do though:

(defpackage :org.tfeb.grub
  (:use)
  (:export #:make-grub #:set-fire-to-grub #:eat-grub))

(defpackage :org.tfeb.grub.implementation
  ;; *don't* use :org.tfeb.grub!
  (:use ... )
  ;; No exports
  (:export))

(in-package :org.tfeb.grub.implementation)

(defun internal-function (...)
  ...
  (org.tfeb.grub:make-grub ...) ; hey, an exported name
  ...)

(defun org.tfeb.grub:set-fire-to-grub (...)
  ;; could this be an exported function?
  ...)

--tim
From: Alexander Schmolck
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <yfsu0ykdwf6.fsf@black132.ex.ac.uk>
··········@tfeb.org (Tim Bradshaw) writes:

> Well, I write a lot of python at the moment, and it's *horrible*
> having to remember that all your unexported names should be _*, or
> forgetting that and exporting stuff you didn't mean to.  I *really
> like* something at the start of a module which says `these are the
> names this thing exports'.

So why not put, at the start of module.py:

__all__ = ['name_that_I_export1', 'name_that_I_export2', ...]

?

'as
From: Tim Bradshaw
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <ey3zn8bpkb5.fsf@cley.com>
* Alexander Schmolck wrote:
> So why not put, at the start of module.py:

> __all__ = ['name_that_I_export1', 'name_that_I_export2', ...]

I didn't know about that!  Now I can do DEFPACKAGE in Python, thanks!
From: ·········@random-state.net
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <c80je0$a7mc3$1@midnight.cs.hut.fi>
Tim Bradshaw <··········@tfeb.org> wrote:

> (defpackage :org.tfeb.grub
>   (:use)
>   (:export #:make-grub #:set-fire-to-grub #:eat-grub))

> (defpackage :org.tfeb.grub.implementation
>   ;; *don't* use :org.tfeb.grub!
>   (:use ... )
>   ;; No exports
>   (:export))

Should I read this as an implicit argument against the following style?

 (defpackage :foo
    (:use)
    (:export #:bar))

 (defpackage :foo-impl 
    (:use :cl :foo))

 (in-package :foo-impl)

 (defun bar () 'foobar!)

 (in-package :cl-user)

 (foo:bar) => FOO-IMPL::FOO-BAR!

If so, could you elaborate? Is it "just" the lack of explicitness at the
definition site?

Cheers,

 -- Nikodemus
From: Tim Bradshaw
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <ey3vfizpjxz.fsf@cley.com>
* nikodemus  wrote:

> Should I read this as an implicit argument against the following style?

>  (defpackage :foo
>     (:use)
>     (:export #:bar))

>  (defpackage :foo-impl 
>     (:use :cl :foo))

>  (in-package :foo-impl)

>  (defun bar () 'foobar!)

No.  I was just saying that if you *want* some kind of explicit marker
in the code for things that are exported, the CL package system can
let you do that.  I'd hate that style personally, but it's there if
anyone wants it.

For what it's worth, I tend to use single packages, or if the
implementation is really hairy I use conduit packages and multiple
implementation packages.

    (defpackage :interface
      (:use)
      (:extends :impl-1 :impl-2))

    ...

--tim
From: Jeff Dalton
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <fx4hduf6b9a.fsf@todday.inf.ed.ac.uk>
Tim Bradshaw <···@cley.com> writes:

> * nikodemus  wrote:
> 
> > Should I read this as an implicit argument against the following style?
> 
> >  (defpackage :foo
> >     (:use)
> >     (:export #:bar))
> 
> >  (defpackage :foo-impl 
> >     (:use :cl :foo))
> 
> >  (in-package :foo-impl)
> 
> >  (defun bar () 'foobar!)

Why would you do that?  I feel something's wrong if you're not
supposed to use a language directly but instead write out some
convention.  For example, the factory, interface, impl one
that many think you should use in Java.  There must be something
wrong with Java, it seems to me, if you have to do that.

> No.  I was just saying that if you *want* some kind of explicit marker
> in the code for things that are exported, the CL package system can
> let you do that.  I'd hate that style personally, but it's there if
> anyone wants it.
> 
> For what it's worth, I tend to use single packages, or if the
> implementation is really hairy I use conduit packages and multiple
> implementation packages.
> 
>     (defpackage :interface
>       (:use)
>       (:extends :impl-1 :impl-2))
> 
>     ...

What the heck is a conduit package?

-- jd
From: Pascal Costanza
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <c89p34$ae3$1@newsreader2.netcologne.de>
Jeff Dalton wrote:

> What the heck is a conduit package?

See http://www.tfeb.org/lisp/hax.html#CONDUITS


Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: Jeff Dalton
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <fx4iseuaoff.fsf@todday.inf.ed.ac.uk>
Pascal Costanza <········@web.de> writes:

> Jeff Dalton wrote:
> 
> > What the heck is a conduit package?
> 
> See http://www.tfeb.org/lisp/hax.html#CONDUITS

Thanks.  Looks v. useful.

Now, is there a nice solution to the problem: I meant to
use-package FOO, I type in some expressions that use symbols
I think are in FOO, but I didn't actually use FOO, so they
aren't; and if I try to use-package FOO now, I get name-conflicts?

Cheers,
JD
From: Pascal Costanza
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <c8b2lc$59u$1@newsreader2.netcologne.de>
Jeff Dalton wrote:

> Pascal Costanza <········@web.de> writes:
> 
>>Jeff Dalton wrote:
>>
>>>What the heck is a conduit package?
>>
>>See http://www.tfeb.org/lisp/hax.html#CONDUITS
> 
> Thanks.  Looks v. useful.
> 
> Now, is there a nice solution to the problem: I meant to
> use-package FOO, I type in some expressions that use symbols
> I think are in FOO, but I didn't actually use FOO, so they
> aren't; and if I try to use-package FOO now, I get name-conflicts?

Yes, but your development environment will most probably offer a 
sensible restart that does the right thing. Just try it out.


Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: Svein Ove Aas
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <vcaqc.2099$RL3.55810@news2.e.nsc.no>
Jeff Dalton wrote:

> Pascal Costanza <········@web.de> writes:
> 
>> Jeff Dalton wrote:
>> 
>> > What the heck is a conduit package?
>> 
>> See http://www.tfeb.org/lisp/hax.html#CONDUITS
> 
> Thanks.  Looks v. useful.
> 
> Now, is there a nice solution to the problem: I meant to
> use-package FOO, I type in some expressions that use symbols
> I think are in FOO, but I didn't actually use FOO, so they
> aren't; and if I try to use-package FOO now, I get name-conflicts?

Having done this myself, you'll probably get several options on how to
continue; one of them is likely along the lines of "override the current
bindings".
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <EU5pc.3029$Yg.1455@fed1read05>
Tim Bradshaw wrote:

> Ari Johnson <·····@hotmail.com> wrote in message news:<······················@fed1read03>...
> 
> 
>>Another thing I don't like is having to list all the exported symbols in 
>>more or less one place.  This makes it harder to tell if a function is 
>>exported just by looking at the function, making it harder to read code.
>>
> 
> 
> Well, I write a lot of python at the moment, and it's *horrible*
> having to remember that all your unexported names should be _*, or
> forgetting that and exporting stuff you didn't mean to.  I *really
> like* something at the start of a module which says `these are the
> names this thing exports'.
> 
> If you want this kind of thing in CL it's fairly easy to do though:
> 
> (defpackage :org.tfeb.grub
>   (:use)
>   (:export #:make-grub #:set-fire-to-grub #:eat-grub))
> 
> (defpackage :org.tfeb.grub.implementation
>   ;; *don't* use :org.tfeb.grub!
>   (:use ... )
>   ;; No exports
>   (:export))
> 
> (in-package :org.tfeb.grub.implementation)
> 
> (defun internal-function (...)
>   ...
>   (org.tfeb.grub:make-grub ...) ; hey, an exported name
>   ...)
> 
> (defun org.tfeb.grub:set-fire-to-grub (...)
>   ;; could this be an exported function?
>   ...)

I didn't know you could do that, thanks.  Also, is dotted-list with 
top-level hierarchy listed first (package, package.subpackage, 
package.subpackage.implementation) considered good form, or is there not 
a preferred naming convention in this area?  Moreover, is having a 
separate package for the implementation of another considered good form?
From: Thomas F. Burdick
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <xcvsme5xng8.fsf@famine.OCF.Berkeley.EDU>
Ari Johnson <·····@hotmail.com> writes:

> Marco Antoniotti wrote:
> > 1 - encapsulation in CL is achieved through packages.
> 
> Is this a cry against objects?

No, it's a cry for objects being objects.  And, generic functions,
GFs, and namespaces namespaces.  C++ tries to make objects all three
things, but Lisp keeps them separate.  It's not a bad thing at all --
export the symbols that name the slots, accessors, and other GFs and
functions you want to expose as your interface; keep the rest internal
to your package.

When I, as a user, use your (or my own) library, if I find myself
needing to do something that you (or I) didn't forsee, I might need to
use symbols internal to your package, but by typing ::, I know I'm
doing something Dirty and Wrong.  If the original designer had had
more foresight, I wouldn't be in this position.  But it's way better
than, "oh, I can't use this."

  Certainly, many languages encourage bad 
> judgement as to what should be an object.  I do think that CL's package 
> system seems a little subpar regarding how cleanly a package and its 
> contents are defined, but I suppose that's necessary to facilitate 
> interaction with the REPL (it'd be a lot harder if you had to do 
> (in-package "package" (code)) every line).

The package system seems to be one of those things that takes a while
to "click" for people.  Not sure why, because I can't remember what my
misconceptions were before it clicked for me.  It does have problems,
but trust that it's perfectly okay, until you're comfortable with it.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <yHzoc.124588$Jy3.5825@fed1read03>
Thomas F. Burdick wrote:

> Ari Johnson <·····@hotmail.com> writes:
> 
> 
>>Marco Antoniotti wrote:
>>
>>>1 - encapsulation in CL is achieved through packages.
>>
>>Is this a cry against objects?
> 
> 
> No, it's a cry for objects being objects.  And, generic functions,
> GFs, and namespaces namespaces.  C++ tries to make objects all three
> things, but Lisp keeps them separate.  It's not a bad thing at all --
> export the symbols that name the slots, accessors, and other GFs and
> functions you want to expose as your interface; keep the rest internal
> to your package.
> 
> When I, as a user, use your (or my own) library, if I find myself
> needing to do something that you (or I) didn't forsee, I might need to
> use symbols internal to your package, but by typing ::, I know I'm
> doing something Dirty and Wrong.  If the original designer had had
> more foresight, I wouldn't be in this position.  But it's way better
> than, "oh, I can't use this."

I like enforcing what's accessible outside my package, but I also like 
writing good interfaces to my packages.  Regarding namespaces being 
objects, that is not the case in C++.

> 
>   Certainly, many languages encourage bad 
> 
>>judgement as to what should be an object.  I do think that CL's package 
>>system seems a little subpar regarding how cleanly a package and its 
>>contents are defined, but I suppose that's necessary to facilitate 
>>interaction with the REPL (it'd be a lot harder if you had to do 
>>(in-package "package" (code)) every line).
> 
> 
> The package system seems to be one of those things that takes a while
> to "click" for people.  Not sure why, because I can't remember what my
> misconceptions were before it clicked for me.  It does have problems,
> but trust that it's perfectly okay, until you're comfortable with it.

I'm sure the main reason it has any of the attributes it does is because 
of the interactive nature of Lisping, but that doesn't make it any cleaner.
From: Jacek Generowicz
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <tyfoeospzoq.fsf@pcepsft001.cern.ch>
Ari Johnson <·····@hotmail.com> writes:

> I like enforcing what's accessible outside my package

I wonder how much your package's clients like you for it.

(If they've bought into the C++ philosophy then they've been
brainwashed into relishing such bondage, so they'll love you for the
pain you're inflicting on them ... but how about intelligent humans
with a working mind of their own ? :-)
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <akGoc.126212$Jy3.3305@fed1read03>
Jacek Generowicz wrote:
> Ari Johnson <·····@hotmail.com> writes:
> 
> 
>>I like enforcing what's accessible outside my package
> 
> 
> I wonder how much your package's clients like you for it.
> 
> (If they've bought into the C++ philosophy then they've been
> brainwashed into relishing such bondage, so they'll love you for the
> pain you're inflicting on them ... but how about intelligent humans
> with a working mind of their own ? :-)

You're not giving anything but ad hominem arguments.  I'd be interested 
in hearing your real logic on this, because I do happen to have a 
working mind of my own, and I do happen to believe that a clean and 
complete interface should be the only thing exposed by a package to 
outside packages.
From: Alan Shutko
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <87sme45vic.fsf@wesley.springies.com>
Ari Johnson <·····@hotmail.com> writes:

> [...] and I do happen to believe that a clean and complete interface
> should be the only thing exposed by a package to outside packages.

Well, if a clean and complete interface is exposed, there's no need
for anyone to go digging around, there's no need for outside packages
to go digging around your internal symbols, and there's really no
problem.

But a clean and complete interface is a rare beast, because it's rare
that you can predict all the ways people will want to use your code.
Other languages acknowledge this: inheritance is designed to help
with this problem.  The difference between Lisp and C++ or Java is
that C++ and Java can allow or disallow this escape hatch.  But
using final can often cause problems... look at how many people
complain they can't subclass String or StringBuffer.

-- 
Alan Shutko <···@acm.org> - I am the rocks.
... We really didn't need a Cleric anyway. (Famous Last Words)
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <PBMoc.126223$Jy3.17322@fed1read03>
Alan Shutko wrote:
> But a clean and complete interface is a rare beast, because it's rare
> that you can predict all the ways people will want to use your code.
> Other languages acknowledge this: inheritance is designed to help
> with this problem.  The difference between Lisp and C++ or Java is
> that C++ and Java can allow or disallow this escape hatch.  But
> using final can often cause problems... look at how many people
> complain they can't subclass String or StringBuffer.

I've never had that complaint, probably because I avoid Java. :D

I agree that predicting all the ways people will want to use my code is 
not easy, *if* my code is to be released publicly.  Within a closed 
environment, however, I can ask the exact people who will be using my 
code how they will use it, and then hold them to that.
From: Jacek Generowicz
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <tyflljvnryz.fsf@pcepsft001.cern.ch>
Ari Johnson <·····@hotmail.com> writes:

> I agree that predicting all the ways people will want to use my code
> is not easy, *if* my code is to be released publicly.  Within a closed
> environment, however, I can ask the exact people who will be using my
> code how they will use it, and then hold them to that.

Unfortunately, those people are no more clairvoyant than you are, so
you haven't really gained much ... other that the right to say "Tough
shit, you should have thought of it earlier" when someone comes along
asking you to fix your interface.
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <hf6pc.3415$Yg.1138@fed1read05>
Jacek Generowicz wrote:

> Ari Johnson <·····@hotmail.com> writes:
> 
> 
>>I agree that predicting all the ways people will want to use my code
>>is not easy, *if* my code is to be released publicly.  Within a closed
>>environment, however, I can ask the exact people who will be using my
>>code how they will use it, and then hold them to that.
> 
> 
> Unfortunately, those people are no more clairvoyant than you are, so
> you haven't really gained much ... other that the right to say "Tough
> shit, you should have thought of it earlier" when someone comes along
> asking you to fix your interface.

But I like doing that to people! ;-D
From: Brian Downing
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <VyGoc.38706$xw3.2524389@attbi_s04>
In article <·····················@fed1read03>,
Ari Johnson  <·····@hotmail.com> wrote:
> You're not giving anything but ad hominem arguments.  I'd be interested 
> in hearing your real logic on this, because I do happen to have a 
> working mind of my own, and I do happen to believe that a clean and 
> complete interface should be the only thing exposed by a package to 
> outside packages.

Well, here's an example which always impressed me.

Lets pretend you've written a really nice regular expression library.
Imagine for a second the perfect interface that you would put on to it.
Once you've got a basic idea for an interface and its scope, read on.

...

...

...

Okay, now lets say I want to write something like The Regex Coach
(http://weitz.de/regex-coach/) with your regex library.  This involves
hooking all over the place to implement a regex stepper and debugger of
sorts.  (Try it, it's quite impressive!)

Now, with your perfect interface you generated in the thought experiment
above, tell me how I'd implement this.

With CL, though it may tie it to internal functionality of your library,
it can at least be done at all.

This is from Edi Weitz's Technical Information section on the Regex
Coach page:

    It might be worthwhile to note that due to the dynamic nature of
    Lisp The Regex Coach could be written without changing a single line
    of code in the CL-PPCRE engine itself although the application has
    to track information and query the engine while the regular
    expressions is parsed and the scanners are built. All this could be
    done 'after the fact' by using facilities like defadvice and :around
    methods. Imagine writing this application in Perl without touching
    Perl's regex engine... :)

Perhaps Edi can comment on this.  Would you have been able to do the
above if you couldn't access internal symbols to wrap?  (Pretend you
didn't write CL-PPCRE as well and can in fact make whatever you want
external.  :)

-bcd
-- 
*** Brian Downing <bdowning at lavos dot net> 
From: Edi Weitz
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <m33c64r9i5.fsf@bird.agharta.de>
On Thu, 13 May 2004 08:43:37 GMT, Brian Downing <·············@lavos.net> wrote:

> Perhaps Edi can comment on this.  Would you have been able to do the
> above if you couldn't access internal symbols to wrap?  (Pretend you
> didn't write CL-PPCRE as well and can in fact make whatever you want
> external.  :)

You're right, I had to use internal symbols. Of course, it was also
helpful that I knew the guy who wrote CL-PPCRE, but his recollection
was kinda foggy... :)

Cheers,
Edi.
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <XZ5pc.3121$Yg.2782@fed1read05>
Christopher C. Stacy wrote:
>  Ari> You're not giving anything but ad hominem arguments.
>  Ari> I'd be interested in hearing your real logic on this, because I do
>  Ari> happen to have a working mind of my own, and I do happen to
>  Ari> believe that a clean and complete interface should be the only
>  Ari> thing exposed by a package to outside packages.
> 
> I'm sure anyone would agree, but not absolutely.  
> Search this newsgroup on Google for discussions about "sealing" 
> and "package locking".

I'll look into that, thanks.

> But more to the point: if you publish your interface (through the
> package system, and more importantly through documentation that says
> what the interface is), why do you need for the language to further
> enforce it?  Wouldn't it be better to leave the emergency escape hatch, 
> in case you hadn't perfectly thought of everything?
> 
> Can you provide a real example where this is a problem?

Yes:  It's a problem when anyone uses my package outside the scope of 
its interface and then comes knocking on my door when I change the 
implementation and their code no longer works.
From: Jacek Generowicz
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <tyf4qqjngfn.fsf@pcepsft001.cern.ch>
Ari Johnson <·····@hotmail.com> writes:

> Yes:  It's a problem when anyone uses my package outside the scope of
> its interface and then comes knocking on my door when I change the
> implementation and their code no longer works.

Aaah, isn't there an international law stating that you can shoot the
person in such a situation?  I gather that Tim B has a selection of
weapons he would probably be glad to lend you.
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <ck6pc.3497$Yg.2035@fed1read05>
Jacek Generowicz wrote:

> Ari Johnson <·····@hotmail.com> writes:
> 
> 
>>Yes:  It's a problem when anyone uses my package outside the scope of
>>its interface and then comes knocking on my door when I change the
>>implementation and their code no longer works.
> 
> 
> Aaah, isn't there an international law stating that you can shoot the
> person in such a situation?  I gather that Tim B has a selection of
> weapons he would probably be glad to lend you.

Not necessary - I have more. :D
From: Christopher C. Stacy
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <uisexblkl.fsf@news.dtpq.com>
>>>>> On Fri, 14 May 2004 08:55:57 -0700, Ari Johnson ("Ari") writes:

 Ari> Christopher C. Stacy wrote:
 Ari> You're not giving anything but ad hominem arguments.
 Ari> I'd be interested in hearing your real logic on this, because I do
 Ari> happen to have a working mind of my own, and I do happen to
 Ari> believe that a clean and complete interface should be the only
 Ari> thing exposed by a package to outside packages.
 >> I'm sure anyone would agree, but not absolutely.  Search this
 >> newsgroup on Google for discussions about "sealing" and "package
 >> locking".

 Ari> I'll look into that, thanks.

 >> But more to the point: if you publish your interface (through the
 >> package system, and more importantly through documentation that says
 >> what the interface is), why do you need for the language to further
 >> enforce it?  Wouldn't it be better to leave the emergency escape
 >> hatch, in case you hadn't perfectly thought of everything?
 >> Can you provide a real example where this is a problem?

 Ari> Yes: It's a problem when anyone uses my package outside the
 Ari> scope of its interface and then comes knocking on my door when I
 Ari> change the implementation and their code no longer works.

Presumably you are charging them money for this support contract, 
so they're just paying you for your time to tell them, "You are 
not calling the published interface, and what you are doing is 
not supported,"  I would make sure to charge them a lot.
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <Qgtpc.161413$f_5.92562@lakeread01>
Christopher C. Stacy wrote:
>>>>>>On Fri, 14 May 2004 08:55:57 -0700, Ari Johnson ("Ari") writes:
> 
> 
>  Ari> Christopher C. Stacy wrote:
>  Ari> You're not giving anything but ad hominem arguments.
>  Ari> I'd be interested in hearing your real logic on this, because I do
>  Ari> happen to have a working mind of my own, and I do happen to
>  Ari> believe that a clean and complete interface should be the only
>  Ari> thing exposed by a package to outside packages.
>  >> I'm sure anyone would agree, but not absolutely.  Search this
>  >> newsgroup on Google for discussions about "sealing" and "package
>  >> locking".
> 
>  Ari> I'll look into that, thanks.
> 
>  >> But more to the point: if you publish your interface (through the
>  >> package system, and more importantly through documentation that says
>  >> what the interface is), why do you need for the language to further
>  >> enforce it?  Wouldn't it be better to leave the emergency escape
>  >> hatch, in case you hadn't perfectly thought of everything?
>  >> Can you provide a real example where this is a problem?
> 
>  Ari> Yes: It's a problem when anyone uses my package outside the
>  Ari> scope of its interface and then comes knocking on my door when I
>  Ari> change the implementation and their code no longer works.
> 
> Presumably you are charging them money for this support contract, 
> so they're just paying you for your time to tell them, "You are 
> not calling the published interface, and what you are doing is 
> not supported,"  I would make sure to charge them a lot.

Who ever said that a Lisp hacker can't have the mindset for upper 
management? ;)
From: Alain Picard
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <877jvgj59i.fsf@memetrics.com>
······@news.dtpq.com (Christopher C. Stacy) writes:

> But more to the point: if you publish your interface (through the
> package system, and more importantly through documentation that says
> what the interface is), why do you need for the language to further
> enforce it?  Wouldn't it be better to leave the emergency escape hatch, 
> in case you hadn't perfectly thought of everything?
>
> Can you provide a real example where this is a problem?

The following story is not a joke.

I worked at a place (a C++ shop) where a programmer not only
violated the #define private encapsulation of an auto_ptr<> style
class, he stashed away the raw pointer for his own use later on.
Needless to say, when the auto_ptr deleted the object before his
little part of the app did, core dumps ensued.

Now, the moral of this isn't to say we need more encapsulation
(we don't), but to illustrate that in the "Real World (TM)", even
proven idiots are allowed access to the keyboard and CVS repositories.
I can _assure_ you that there would be no way to get this guy fired
for incompetence; he was easily in the top half of programming
talent (in that shop).  :-(

I think it's hard for the average lisper to realize just how
low the standard for competence is in the IT industry.  I had
endless discussions with the system architects about how do
design "idiot-proof" interfaces, and they never seemed to accept
my recommendation of taking the keyboards away from the idiots.
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <926pc.3191$Yg.1047@fed1read05>
Alain Picard wrote:

> ······@news.dtpq.com (Christopher C. Stacy) writes:
> 
> 
>>But more to the point: if you publish your interface (through the
>>package system, and more importantly through documentation that says
>>what the interface is), why do you need for the language to further
>>enforce it?  Wouldn't it be better to leave the emergency escape hatch, 
>>in case you hadn't perfectly thought of everything?
>>
>>Can you provide a real example where this is a problem?
> 
> 
> The following story is not a joke.
> 
> I worked at a place (a C++ shop) where a programmer not only
> violated the #define private encapsulation of an auto_ptr<> style
> class, he stashed away the raw pointer for his own use later on.
> Needless to say, when the auto_ptr deleted the object before his
> little part of the app did, core dumps ensued.
> 
> Now, the moral of this isn't to say we need more encapsulation
> (we don't), but to illustrate that in the "Real World (TM)", even
> proven idiots are allowed access to the keyboard and CVS repositories.
> I can _assure_ you that there would be no way to get this guy fired
> for incompetence; he was easily in the top half of programming
> talent (in that shop).  :-(
> 
> I think it's hard for the average lisper to realize just how
> low the standard for competence is in the IT industry.  I had
> endless discussions with the system architects about how do
> design "idiot-proof" interfaces, and they never seemed to accept
> my recommendation of taking the keyboards away from the idiots.

I realize exactly how bad it is in the IT industry, and that's why I'm 
getting out.  As a result, I'm learning Lisp, because it's the language 
of enlightenment and I'm not moving on until I internalize that 
enlightenment.  Plus, I don't have to worry about if it'll get me a job 
ever, so I can learn it uninhindered by employment. :)
From: Marco Baringer
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <m2pt96rdvq.fsf@bese.it>
Alain Picard <············@memetrics.com> writes:

> ······@news.dtpq.com (Christopher C. Stacy) writes:
>
>> But more to the point: if you publish your interface (through the
>> package system, and more importantly through documentation that says
>> what the interface is), why do you need for the language to further
>> enforce it?  Wouldn't it be better to leave the emergency escape hatch, 
>> in case you hadn't perfectly thought of everything?
>>
>> Can you provide a real example where this is a problem?
>
> The following story is not a joke.

[snip - a story about a normal day in a normal shop]

um, and the point of helping these kinds of programmers is what?

I refuse to fix, help fixing, support fixing, or even think about
fixing the elevator on the titanic.

-- 
-Marco
Ring the bells that still can ring.
Forget your perfect offering.
There is a crack in everything.
That's how the light gets in.
     -Leonard Cohen
From: Jacek Generowicz
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <tyfpt97ns5h.fsf@pcepsft001.cern.ch>
Ari Johnson <·····@hotmail.com> writes:

> You're not giving anything but ad hominem arguments.  I'd be
> interested in hearing your real logic on this, because I do happen to
> have a working mind of my own, and I do happen to believe that a clean
> and complete interface should be the only thing exposed by a package
> to outside packages.

I would claim that you have never written a (significant) clean and
_complete_ interface. There is nothing ad hominem about this; I would
make the same claim about any programmer, including myself.

I am quite confident that my sweeping generalization is not too far
off the truth, because few programmers have the benefit of designing
their interfaces with the benefit of _complete_ hindsight. You simply
cannot imagine what sort of (perfectly reasonable) things people might
wish to do with your libraries.

But even if the "clean and complete" interface exists ... imagine you
are writing client code to that interface. Odds on that at some stage
you will be doing some debugging or other investigation of the
behaviour of the program, and to help you do this you may wish to have
a look at what is going on in the internals of the library. You are
perfectly justified to go around the interface in your attempt to
better understand the behaviour of the program you are developing. But
wait, some git is preventing you from seeing this information (unless
you drop into a debugger[*] or "#define private public" etc.): access
restriction is getting in the way of you understanding the behaviour
of your program. That sounds like a great way of decreasing
productivity.

[*] Anyone know of a debugger which hides private data ?
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <Xe6pc.3410$Yg.1262@fed1read05>
Jacek Generowicz wrote:

> Ari Johnson <·····@hotmail.com> writes:
> 
> 
>>You're not giving anything but ad hominem arguments.  I'd be
>>interested in hearing your real logic on this, because I do happen to
>>have a working mind of my own, and I do happen to believe that a clean
>>and complete interface should be the only thing exposed by a package
>>to outside packages.
> 
> 
> I would claim that you have never written a (significant) clean and
> _complete_ interface. There is nothing ad hominem about this; I would
> make the same claim about any programmer, including myself.

Isn't Lisping in part equivalent to living in an ideal world?  That's 
where I was talking from when I made the "clean and complete" statement. 
  Obviously, the real world falls short, but you *can* move where the 
line is drawn.

> I am quite confident that my sweeping generalization is not too far
> off the truth, because few programmers have the benefit of designing
> their interfaces with the benefit of _complete_ hindsight. You simply
> cannot imagine what sort of (perfectly reasonable) things people might
> wish to do with your libraries.
> 
> But even if the "clean and complete" interface exists ... imagine you
> are writing client code to that interface. Odds on that at some stage
> you will be doing some debugging or other investigation of the
> behaviour of the program, and to help you do this you may wish to have
> a look at what is going on in the internals of the library. You are
> perfectly justified to go around the interface in your attempt to
> better understand the behaviour of the program you are developing. But
> wait, some git is preventing you from seeing this information (unless
> you drop into a debugger[*] or "#define private public" etc.): access
> restriction is getting in the way of you understanding the behaviour
> of your program. That sounds like a great way of decreasing
> productivity.

If the interface is perfect (which it isn't, but see above), then the 
implementation can also be assumed to be bug-free and perfectly 
documented, so your example doesn't hold.  However, for all X where 
perfection(X) < 1, this is a legitimate concern.

> [*] Anyone know of a debugger which hides private data ?

I bet Java's does, but I haven't written enough code in Java to care to 
fix my bugs. :)
From: Steven E. Harris
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <q677jvebvsh.fsf@L75001820.us.ray.com>
Jacek Generowicz <················@cern.ch> writes:

> But wait, some git is preventing you from seeing this information
> (unless you drop into a debugger[*] or "#define private public"
> etc.): access restriction is getting in the way of you understanding
> the behaviour of your program.

Why would you need to understand a malfunctioning library when /not/
debugging? As I was reading your problem setup, I kept thinking,
"Sure, you may want to peek inside, and that's when you break out the
debugger."

[...]

> [*] Anyone know of a debugger which hides private data ?

No, I've never seen one. In the C++ debuggers I've used, one can
always look at the private data, but may not be able to interpret it
all sensibly. But looking isn't nearly as dangerous as changing.

-- 
Steven E. Harris        :: ········@raytheon.com
Raytheon                :: http://www.raytheon.com
From: Jacek Generowicz
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <tyf65aykwvp.fsf@lxplus009.cern.ch>
"Steven E. Harris" <········@raytheon.com> writes:

> Why would you need to understand a malfunctioning library when /not/
> debugging? As I was reading your problem setup, I kept thinking,
> "Sure, you may want to peek inside, and that's when you break out the
> debugger."

Who said anything about a malfunctioning library? Assume it's perfect
in both implementation and interface, if you like: you still might
want to track what happens to your data. But being _forced_ to use a
debugger to do this is a PITA. You might want to run the program and
write some data private data out to a log: how many (non-lisp)
debuggers let you do this sort of thing easily ?
From: Svein Ove Aas
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <rA4pc.1482$RL3.33129@news2.e.nsc.no>
Jacek Generowicz wrote:

> [*] Anyone know of a debugger which hides private data ?


Not anymore, but at least one early version of Visual C++ would do just
that, unless you told it not to. Via a registry key.

I had *such* fun explaining to the purchaser why his purchase was utterly
useless for the purpose he had bought it, which happened to be debugging
a library.
From: Svein Ove Aas
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <HE4pc.1485$RL3.33129@news2.e.nsc.no>
Svein Ove Aas wrote:

> Jacek Generowicz wrote:
> 
>> [*] Anyone know of a debugger which hides private data ?
> 
> 
> Not anymore, but at least one early version of Visual C++ would do just
> that, unless you told it not to. Via a registry key.
> 
> I had *such* fun explaining to the purchaser why his purchase was
> utterly useless for the purpose he had bought it, which happened to be
> debugging a library.

Note of explanation: He wasn't allowed to modify the registry, under any
circumstances. Oddly enough, he *was* allowed to install any and all MS
software he wanted, under supervision.

I'm very happy I'm not him.
From: Joe Marshall
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <1xlotnbz.fsf@ccs.neu.edu>
Ari Johnson <·····@hotmail.com> writes:

> I like enforcing what's accessible outside my package, but I also like
> writing good interfaces to my packages.

How much enforcement do you want?

At one company I worked at it was considered very poor style to use
non-exported symbols and you would have to justify doing so during
code review.  Programmers that could not follow directions were asked
to leave.
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <ePMoc.126228$Jy3.23966@fed1read03>
Joe Marshall wrote:

> Ari Johnson <·····@hotmail.com> writes:
> 
> 
>>I like enforcing what's accessible outside my package, but I also like
>>writing good interfaces to my packages.
> 
> 
> How much enforcement do you want?
> 
> At one company I worked at it was considered very poor style to use
> non-exported symbols and you would have to justify doing so during
> code review.  Programmers that could not follow directions were asked
> to leave.

Did they have a logical justification for that policy, or were they just 
stupid?
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <sN5pc.2906$Yg.445@fed1read05>
Joe Marshall wrote:
> Ari Johnson <·····@hotmail.com> writes:
> 
> 
>>Joe Marshall wrote:
>>
>>
>>>Ari Johnson <·····@hotmail.com> writes:
>>>
>>>
>>>>I like enforcing what's accessible outside my package, but I also like
>>>>writing good interfaces to my packages.
>>>
>>>How much enforcement do you want?
>>>At one company I worked at it was considered very poor style to use
>>>non-exported symbols and you would have to justify doing so during
>>>code review.  Programmers that could not follow directions were asked
>>>to leave.
>>
>>Did they have a logical justification for that policy, or were they
>>just stupid?
> 
> 
> At every company I worked for it was policy to fire people who were
> insubordinate.  There are many justifications for doing so, but fiscal
> responsibility to shareholders is a good one.

I asked if they had a logical justification for the policy, not whether 
you were dumb enough to confront them about it in an insubordinate way. 
  Most corporate written policies include some clues (or even explicit 
statements) as to why they exist and, even if this one didn't, there are 
fully subordinate ways to inquire.
From: Joe Marshall
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <r7tmg5nb.fsf@ccs.neu.edu>
> Joe Marshall wrote:
>>>> At one company I worked at it was considered very poor style to use
>>>> non-exported symbols and you would have to justify doing so during
>>>> code review.  Programmers that could not follow directions were asked
>>>> to leave.

Ari Johnson <·····@hotmail.com> writes:

> I asked if they had a logical justification for the policy, not
> whether you were dumb enough to confront them about it in an
> insubordinate way.  Most corporate written policies include some clues
> (or even explicit statements) as to why they exist and, even if this
> one didn't, there are fully subordinate ways to inquire.

I thought it was pretty logical:  code conventions, such as not using
non-exported symbols, not putting "#define private public" in header
files, putting copyright notices on source files, naming functions in
a predictable manner, etc. are a common sort of policy to maintain in
a development group.  Some of these things might be enforced by the
language or the tools, but a lot of them like
"WriteYourIdentifiersLikeThis" or "functions that return void must end
in _v" or "compilation must produce no warnings at the most anal
settings" are enforced by policy only.

The `don't use unexported symbols' convention was there so that we
could differentiate between interface and implementation.  When
someone used an unexported symbol, he was violating an agreed upon
published interface.  When this happens, you are exposing yourself to
the risk that the implementation will change, and it seems that such a
risk ought to be discussed in code review.  There are a few solutions:

  1.  Perhaps there is a documented way to obtain the desired
      information without violating the published interface.  The code
      could be modified to not use the internal symbol.

  2.  Perhaps the necessary functionality *ought* to have been
      exported.  The symbol could be exported and documented.

  3.  Perhaps it is just one of those places where deus-ex-machina is
      called for and we'll leave the code alone and put big warning
      labels around it.

So there was the occasional use of an internal symbol, and when that
happened we made sure that everyone knew why.  If you *needed* to use
one, go ahead and use it.  We didn't fire people because they wanted
to use an internal symbol.

But if someone were to *persist* in using internal symbols despite
alternative suggestions and refused to document or tell anyone about
such use, I think it is reasonable to ask them to consider other
employment.

Enforcing protection through the compiler doesn't really help here.
If the programmer is responsible, he doesn't need to be monitored by
the compiler every step of the way.  If the programmer is perverse,
however, he'll just bypass the compiler enforcement and you're screwed
anyway.
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <qOdpc.800$wn1.25@fed1read01>
Joe Marshall wrote:
> The `don't use unexported symbols' convention was there so that we
> could differentiate between interface and implementation.  When
> someone used an unexported symbol, he was violating an agreed upon
> published interface.  When this happens, you are exposing yourself to
> the risk that the implementation will change, and it seems that such a
> risk ought to be discussed in code review.  There are a few solutions:

Oh my, I misunderstood your original statement.  I thought you meant 
"don't use unexported symbols" in the sense that you were not allowed to 
have symbols that you didn't export.  Quite a difference in meaning, eh?
From: Joe Marshall
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <ad078buk.fsf@ccs.neu.edu>
Ari Johnson <·····@hotmail.com> writes:

> Joe Marshall wrote:
>> The `don't use unexported symbols' convention was there so that we
>> could differentiate between interface and implementation.  When
>> someone used an unexported symbol, he was violating an agreed upon
>> published interface.  When this happens, you are exposing yourself to
>> the risk that the implementation will change, and it seems that such a
>> risk ought to be discussed in code review.  There are a few solutions:
>
> Oh my, I misunderstood your original statement.  I thought you meant
> "don't use unexported symbols" in the sense that you were not allowed
> to have symbols that you didn't export.  Quite a difference in
> meaning, eh?

Yes.
From: Karl A. Krueger
Subject: Grokking packages
Date: 
Message-ID: <c7uks3$q1g$1@baldur.whoi.edu>
Thomas F. Burdick <···@famine.ocf.berkeley.edu> wrote:
> The package system seems to be one of those things that takes a while
> to "click" for people.  Not sure why, because I can't remember what my
> misconceptions were before it clicked for me.  It does have problems,
> but trust that it's perfectly okay, until you're comfortable with it.

I'm not about to claim that I grok packages, but one thing that made
them a lot less mysterious to me was understanding -symbols- a little
more.  "Symbol" is a very meaning-laden word, and Lisp uses it to mean
a peculiar [1] data structure -- one just as closely nestled in the
language as are conses and lists.

My first impression of symbols was that they were identifiers -- strings
treated specially by the Lisp system.  My second was that they were
somehow -also- used for many of the things Python uses empty classes
for: thus, that they were named objects with identity.  Then I read Paul
Graham's description of them in _ANSI Common Lisp_, and started fooling
around with property lists.  I -think- I get the idea of symbols now.

They're a sort of data structure which most other languages don't let
you at.  They're logically what "symbol tables" are made of, in
compilers like C's, except C doesn't let you dig into them and use them
for your own purposes.  C compilers use them internally to map names to
places.  Lisp lets you the user use them to do the same ... and other
things as well.

My current understanding of packages is that they are associations of
strings to symbols.  I can look a symbol up in a package with INTERN,
and get the string back from a symbol with SYMBOL-NAME.  I can create a
package and intern symbols in it to cache things and share them among
mod_lisp threads.  The Lisp system has a current package which is the
default for new symbols.  If I create some new symbols with INTERN or by
typing things into the REPL, they get stuck in that package unless I
specify otherwise.  There are uninterned symbols, too, which have names
only lexically within macros (GENSYM) -- but I haven't written any
production macros significant enough to need them, yet.

[1] In the sense of "distinct", not "bizarre".

-- 
Karl A. Krueger <········@example.edu>
Woods Hole Oceanographic Institution
Email address is spamtrapped.  s/example/whoi/
"Outlook not so good." -- Magic 8-Ball Software Reviews
From: mikel
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <Dwtoc.7545$mk6.6738@newssvr27.news.prodigy.com>
Ari Johnson wrote:
> Marco Antoniotti wrote:
> 
>> 1 - encapsulation in CL is achieved through packages.
> 
> 
> Is this a cry against objects?  Certainly, many languages encourage bad 
> judgement as to what should be an object.  I do think that CL's package 
> system seems a little subpar regarding how cleanly a package and its 
> contents are defined, but I suppose that's necessary to facilitate 
> interaction with the REPL (it'd be a lot harder if you had to do 
> (in-package "package" (code)) every line).

In some languages, class or object boundaries are also encapsulating 
boundaries; not so in Common Lisp. Common Lisp provides facilities for 
procedural and data abstraction, but only weak facilities for 
enncapsulation because, ultimately, you don't want things to be *really* 
encapsulated; if they were, you couldn't inspect and change them, and 
interactive Lisp programming is all about inspecting and changing things.

You can *suggest* that you want things to be encapsulated by putting 
them in a package and not exporting them (though a programmer determined 
to ignore your suggestions can use them anyway). If you *really* want to 
hide things, you can stick them inside lexical closures where the only 
thing that can see them is the closed function.

Common Lisp just doesn't try all that hard to support enncapsulation.

Note also that, logically speaking, encapsulation is orthogonal to class 
and object boundaries. Dylan was designed to keep them orthogonal, so 
that you could define an inheritance heterarchy and use modules to draw 
the boundaries of encapsulation wherever you wanted.
From: Jacek Generowicz
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <tyfsme4pzx3.fsf@pcepsft001.cern.ch>
mikel <·····@evins.net> writes:

> In some languages, class or object boundaries are also encapsulating
> boundaries; not so in Common Lisp. Common Lisp provides facilities for
> procedural and data abstraction, but only weak facilities for
> enncapsulation because, ultimately, you don't want things to be
> *really* encapsulated; if they were, you couldn't inspect and change
> them, and interactive Lisp programming is all about inspecting and
> changing things.

Am I the last person left on the planet who thinks that
"encapsulation" is not synonymous with "access restriction" ?

I consider encapsulation to be far closer to data abstraction than
access restriction. The whole "privacy" concept seems to be yet
another productivity reduction mechanism built in to C++ (and its
clones ... though I guess C++ didn't actually invent it.)
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <7zFoc.126085$Jy3.100707@fed1read03>
Jacek Generowicz wrote:
> mikel <·····@evins.net> writes:
> 
> 
>>In some languages, class or object boundaries are also encapsulating
>>boundaries; not so in Common Lisp. Common Lisp provides facilities for
>>procedural and data abstraction, but only weak facilities for
>>enncapsulation because, ultimately, you don't want things to be
>>*really* encapsulated; if they were, you couldn't inspect and change
>>them, and interactive Lisp programming is all about inspecting and
>>changing things.
> 
> 
> Am I the last person left on the planet who thinks that
> "encapsulation" is not synonymous with "access restriction" ?
> 
> I consider encapsulation to be far closer to data abstraction than
> access restriction. The whole "privacy" concept seems to be yet
> another productivity reduction mechanism built in to C++ (and its
> clones ... though I guess C++ didn't actually invent it.)

How does it reduce your productivity?  Presume that you're working with 
a large group of programmers.  Being able to specify an interface and 
rely on them not using any internals of your package other than through 
its interface will increase your productivity by reducing the number of 
possible bugs at the package boundary.

I do agree, though, that access restriction is not tantamount to 
encapsulation.  It's just an easy feature to add.
From: Pascal Costanza
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <c7va5u$7r8$3@newsreader2.netcologne.de>
Ari Johnson wrote:

> Jacek Generowicz wrote:

>> I consider encapsulation to be far closer to data abstraction than
>> access restriction. The whole "privacy" concept seems to be yet
>> another productivity reduction mechanism built in to C++ (and its
>> clones ... though I guess C++ didn't actually invent it.)
> 
> How does it reduce your productivity?  Presume that you're working with 
> a large group of programmers.  Being able to specify an interface and 
> rely on them not using any internals of your package other than through 
> its interface will increase your productivity by reducing the number of 
> possible bugs at the package boundary.

This only works if you have gotten your interfaces perfectly right. The 
CL package model is a solution for the cases in which you are convinced 
that an unexported symbol should really be exported: Just use it, and 
report to the designer of the library that you need that feature. Go 
ahead with your own stuff then. Don't wait for 1.5 years just because 
your vendor takes that long to produce a new version. ;)

> I do agree, though, that access restriction is not tantamount to 
> encapsulation.  It's just an easy feature to add.

Not everything that is easy to add is a good idea.


Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <QmGoc.126213$Jy3.11039@fed1read03>
Pascal Costanza wrote:

> 
> 
> Ari Johnson wrote:
> 
>> Jacek Generowicz wrote:
> 
> 
>>> I consider encapsulation to be far closer to data abstraction than
>>> access restriction. The whole "privacy" concept seems to be yet
>>> another productivity reduction mechanism built in to C++ (and its
>>> clones ... though I guess C++ didn't actually invent it.)
>>
>>
>> How does it reduce your productivity?  Presume that you're working 
>> with a large group of programmers.  Being able to specify an interface 
>> and rely on them not using any internals of your package other than 
>> through its interface will increase your productivity by reducing the 
>> number of possible bugs at the package boundary.
> 
> 
> This only works if you have gotten your interfaces perfectly right. The 
> CL package model is a solution for the cases in which you are convinced 
> that an unexported symbol should really be exported: Just use it, and 
> report to the designer of the library that you need that feature. Go 
> ahead with your own stuff then. Don't wait for 1.5 years just because 
> your vendor takes that long to produce a new version. ;)
> 
>> I do agree, though, that access restriction is not tantamount to 
>> encapsulation.  It's just an easy feature to add.
> 
> 
> Not everything that is easy to add is a good idea.

Nor is the inverse necessarily true.
From: Pascal Costanza
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <c7vd89$epv$1@newsreader2.netcologne.de>
Ari Johnson wrote:

> Pascal Costanza wrote:

>> This only works if you have gotten your interfaces perfectly right. 
>> The CL package model is a solution for the cases in which you are 
>> convinced that an unexported symbol should really be exported: Just 
>> use it, and report to the designer of the library that you need that 
>> feature. Go ahead with your own stuff then. Don't wait for 1.5 years 
>> just because your vendor takes that long to produce a new version. ;)
>>
>>> I do agree, though, that access restriction is not tantamount to 
>>> encapsulation.  It's just an easy feature to add.
>>
>> Not everything that is easy to add is a good idea.
> 
> Nor is the inverse necessarily true.

"Not everything that is a good idea is easy to add."? Yep, I agree. ;)


Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <kxMoc.126222$Jy3.58803@fed1read03>
Pascal Costanza wrote:
> 
> 
> Ari Johnson wrote:
> 
>> Pascal Costanza wrote:
> 
> 
>>> This only works if you have gotten your interfaces perfectly right. 
>>> The CL package model is a solution for the cases in which you are 
>>> convinced that an unexported symbol should really be exported: Just 
>>> use it, and report to the designer of the library that you need that 
>>> feature. Go ahead with your own stuff then. Don't wait for 1.5 years 
>>> just because your vendor takes that long to produce a new version. ;)
>>>
>>>> I do agree, though, that access restriction is not tantamount to 
>>>> encapsulation.  It's just an easy feature to add.
>>>
>>>
>>> Not everything that is easy to add is a good idea.
>>
>>
>> Nor is the inverse necessarily true.
> 
> 
> "Not everything that is a good idea is easy to add."? Yep, I agree. ;)

No, rather: "Everything that is easy to add is not a good idea." is the 
inverse, which is what I was saying isn't true.  You're going with the 
contrapositive, which is always true.
From: Svein Ove Aas
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <wO4pc.1488$RL3.33129@news2.e.nsc.no>
Ari Johnson wrote:

> Pascal Costanza wrote:
>> 
>> 
>> Ari Johnson wrote:
>> 
>>> Pascal Costanza wrote:
>> 
>> 
>>>> This only works if you have gotten your interfaces perfectly right.
>>>> The CL package model is a solution for the cases in which you are
>>>> convinced that an unexported symbol should really be exported: Just
>>>> use it, and report to the designer of the library that you need that
>>>> feature. Go ahead with your own stuff then. Don't wait for 1.5 years
>>>> just because your vendor takes that long to produce a new version. ;)
>>>>
>>>>> I do agree, though, that access restriction is not tantamount to
>>>>> encapsulation.  It's just an easy feature to add.
>>>>
>>>>
>>>> Not everything that is easy to add is a good idea.
>>>
>>>
>>> Nor is the inverse necessarily true.
>> 
>> 
>> "Not everything that is a good idea is easy to add."? Yep, I agree. ;)
> 
> No, rather: "Everything that is easy to add is not a good idea." is the
> inverse, which is what I was saying isn't true.  You're going with the
> contrapositive, which is always true.

Well, I'm sure I could come up with a situation where it wouldn't be a
good idea to add anything at all.

In that case, nothing that could be addded would be hard to add.
From: Jacek Generowicz
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <tyfy8nvnt1d.fsf@pcepsft001.cern.ch>
Ari Johnson <·····@hotmail.com> writes:

> Jacek Generowicz wrote:
>
> > access restriction. The whole "privacy" concept seems to be yet
> > another productivity reduction mechanism built in to C++ (and its
> > clones ... though I guess C++ didn't actually invent it.)
> 
> How does it reduce your productivity?

By making it difficult (by trying to make it impossible, even) to look
at (or modify) something you might want/need to see (or modify).

> Presume that you're working with a large group of programmers.
> Being able to specify an interface and rely on them not using any
> internals of your package other than through its interface will
> increase your productivity by reducing the number of possible bugs
> at the package boundary.

The difference is whether you can rely on your colleagues to respect
the interface or not. If you cannot trust your colleagues to respect
the interface _unless they have a good reason to work around it_ then
you have problems far greater than access restriction can cope with.

If you have a poor programmer, making him wear a straitjacket is not
going going to make him write better code.

If you have a good programmer, making him wear a straitjacket is going
to make him considrably less productive.

> I do agree, though, that access restriction is not tantamount to
> encapsulation.  It's just an easy feature to add.

Easy, but counterproductive.
From: Steven E. Harris
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <q67d656bw3g.fsf@L75001820.us.ray.com>
Jacek Generowicz <················@cern.ch> writes:

> If you have a good programmer, making him wear a straitjacket is
> going to make him considrably less productive.

I still can't see how this is so. If I have data I need to protect to
maintain an observable invariant, how does protecting it hurt me or
anyone else? At least I can eliminate misdirected bug accusations when
a client attempts to tinker with some invariant-critical data.

Consider, say, a vector type in C++.� There is usually an integral
member variable storing the current size of the allocated storage
("capacity"), and another variable storing the current number of valid
elements present ("size"), with the latter necessarily less than or
equal to the former. Valid operations include checking the current
number of valid elements (through a function call), and adding or
deleting an element. The two size variables noted above are
private. They change only in response to certain operations on the
vector.

If those size/count variables can't be made private, or at least
protected from external mutation, how can the vector maintain its
invariants? Or, turn the question around: Why would a client ever want
to directly change the storage size variable? Only ignorance or
malfeasance come to mind. What benefit is there in permitting this
kind of abuse? If I wrote the vector type, how is my productivity
improved with bug reports coming in that manifest violations of my
would-be invariants?


Footnotes: 
� http://www.dinkumware.com/manuals/reader.aspx?b=p/&h=vector.html#vector

-- 
Steven E. Harris        :: ········@raytheon.com
Raytheon                :: http://www.raytheon.com
From: Kenny Tilton
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <j2cpc.67343$Nn4.16257892@twister.nyc.rr.com>
Steven E. Harris wrote:
> Jacek Generowicz <················@cern.ch> writes:
> 
> 
>>If you have a good programmer, making him wear a straitjacket is
>>going to make him considrably less productive.
> 
> 
> I still can't see how this is so. If I have data I need to protect to
> maintain an observable invariant, how does protecting it hurt me or
> anyone else? At least I can eliminate misdirected bug accusations when
> a client attempts to tinker with some invariant-critical data.

I wonder if anyone has done any research in which they attempted to 
determine how often various kinds of bugs occurred. It would be fun also 
to determine how long it takes to solve certain categories of bug.

This whole public-private thing seems like a good idea, but how often 
does a bug result from someone using an accessor they should not have? I 
am not counting willful idiots who make no effort to learn an API, but 
well meaning programmers who accidentally use an internals hook despite 
their best intentions not to. And with Lisp they kinda /know/ they are 
because of the (pkg::sys-shutdown... thng they have to code.

So, out there in the real world of C... this was a big problem? Mind 
you, I realize it helps to /learn/ an API to know which things are not 
part of it, but exported vs not exported handles that.

kt

-- 
Home? http://tilton-technology.com
Cells? http://www.common-lisp.net/project/cells/
Cello? http://www.common-lisp.net/project/cello/
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
Your Project Here! http://alu.cliki.net/Industry%20Application
From: Steven E. Harris
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <q671xlmbnjw.fsf@L75001820.us.ray.com>
Kenny Tilton <·······@nyc.rr.com> writes:

> This whole public-private thing seems like a good idea, but how
> often does a bug result from someone using an accessor they should
> not have?

I don't really know from my own experience, because I lock things down
tight when I'm writing C++. Maybe I'm preemptively avoiding a problem
that wouldn't really come up. But in C++, that kind of defensiveness
is a guiding principle, the flip-side being that the public/private
distinction serves as enforceable documentation, much like const
qualification.


[...]

> exported vs not exported handles that.

I agree, for Common Lisp. Learning that one can obscure -- not hide --
class data and operations with the package system allayed my
C++-prejudiced concerns.

-- 
Steven E. Harris        :: ········@raytheon.com
Raytheon                :: http://www.raytheon.com
From: Kenny Tilton
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <8hhpc.68826$Nn4.16382743@twister.nyc.rr.com>
Steven E. Harris wrote:

> Kenny Tilton <·······@nyc.rr.com> writes:
> 
> 
>>This whole public-private thing seems like a good idea, but how
>>often does a bug result from someone using an accessor they should
>>not have?
> 
> 
> I don't really know from my own experience, because I lock things down
> tight when I'm writing C++.

Right, that's why I said "c". Another category would be C++ folk who 
could not be bothered to use public/private vs const/not.

  Maybe I'm preemptively avoiding a problem
> that wouldn't really come up. But in C++, that kind of defensiveness
> is a guiding principle, the flip-side being that the public/private
> distinction serves as enforceable documentation, much like const
> qualification.

yeah, that one, too, const.

when I see GC, I have no doubt (based on my C experience) that a huge 
win is in hand. When I saw (in Dylan? I forget) that uninitialized 
variables are not allowed, I said to myself (being a C programmer at the 
time) "ok, good, easy enough to do, and yes, I have used local variables 
to which no good value ever got assigned.

But I sure as hell never modified an argument mistakenly thinking the 
caller would notice. As for calling internal hooks, gosh, I'd need the 
source, i would need to ignore the API documentation as well as not 
understand it, and as reckless a programmer as I am, I still don't think 
it would come up so often that I would start to think about building a 
strait-jacket into a language to solve the once-in-a-blue-moon resultant 
bug. hell, i can suffix any internal hook with "-i" and I am good to go, 
if that is such a huge issue.

I am left with the same question: where is the research into programmer 
unproductivity supporting the C++ strait jacket design decisions? Was 
this just stuff that people thought they could enforce, without ever 
worrying if it mattered much, and without considering the cost of such 
constraints?

kt



-- 
Home? http://tilton-technology.com
Cells? http://www.common-lisp.net/project/cells/
Cello? http://www.common-lisp.net/project/cello/
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
Your Project Here! http://alu.cliki.net/Industry%20Application
From: Thomas F. Burdick
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <xcvekplwnn3.fsf@famine.OCF.Berkeley.EDU>
Kenny Tilton <·······@nyc.rr.com> writes:

> Steven E. Harris wrote:
> 
> > Kenny Tilton <·······@nyc.rr.com> writes:
> > 
> >>This whole public-private thing seems like a good idea, but how
> >>often does a bug result from someone using an accessor they should
> >>not have?
> > 
> > I don't really know from my own experience, because I lock things down
> > tight when I'm writing C++.
> 
> Right, that's why I said "c". Another category would be C++ folk who 
> could not be bothered to use public/private vs const/not.

From my own C++ experience, I fell out of love with the careful
planning one was supposed to put into public/protected/private, and
after a while I started making everything public (when it was up to
me).  I'd use naming conventions to indicate what was implementational
details, and what was interface.  I can't think of ever coming across
a bug where I or anyone using a class I wrote accidentally used an
implementational variable or method, thinking it was interface.

> I am left with the same question: where is the research into programmer 
> unproductivity supporting the C++ strait jacket design decisions? Was 
> this just stuff that people thought they could enforce, without ever 
> worrying if it mattered much, and without considering the cost of such 
> constraints?

C++ was designed more by, "Hey, you know what would be a cool
feature," than by research into programmer unproductivity.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Peter Herth
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <c83bqu$b7f$1@newsreader2.netcologne.de>
Steven E. Harris wrote:

> Consider, say, a vector type in C++.� There is usually an integral
> member variable storing the current size of the allocated storage
> ("capacity"), and another variable storing the current number of valid
> elements present ("size"), with the latter necessarily less than or
> equal to the former. Valid operations include checking the current
> number of valid elements (through a function call), and adding or
> deleting an element. The two size variables noted above are
> private. They change only in response to certain operations on the
> vector.

Of course there are situations where private variables seem to be 
the "right way to go". Such a class as described is a good example
for this. And in general, if a class is really "finished" then the
need for accessing private variables should not be there (or it is
not really finished, one could say)

> If those size/count variables can't be made private, or at least
> protected from external mutation, how can the vector maintain its
> invariants? Or, turn the question around: Why would a client ever want
> to directly change the storage size variable? Only ignorance or
> malfeasance come to mind. What benefit is there in permitting this
> kind of abuse? If I wrote the vector type, how is my productivity
> improved with bug reports coming in that manifest violations of my
> would-be invariants?

The benefit of being able to access all variables of a class comes for
example then, when your vector class does have a bug. Then I *might*
need to look into its internals at run time. So I think accessing
private variables of a class should not be the standard practise
of a programmer and thus is not something that influences the productivity
in "normal" day to day work. However, when needed, its an important
thing to have. A typical example is a long running server application,
where you want/need to exchange code during runtime (this is where
Lisp really shines) and due to these changes suddenly need to access
a variable previously thought being proper declared private...
In Java, this happened often enough to me that I am quite glad that
Common Lisp is a little bit more relaxed there. 

Peter

-- 
pet project: http://dawn.netcologne.de
homepage:    http://www.peter-herth.de
lisp stuff:  http://www.peter-herth.de/lisp.html
From: Pascal Costanza
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <c83ie3$mal$1@newsreader2.netcologne.de>
Steven E. Harris wrote:

> Jacek Generowicz <················@cern.ch> writes:
> 
>>If you have a good programmer, making him wear a straitjacket is
>>going to make him considrably less productive.
> 
> I still can't see how this is so. If I have data I need to protect to
> maintain an observable invariant, how does protecting it hurt me or
> anyone else? At least I can eliminate misdirected bug accusations when
> a client attempts to tinker with some invariant-critical data.

Have you never ever made the experience that a library did nearly what 
you wanted and you could use it if only you would be able to fix that 
single wrong behavior?


Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: Jacek Generowicz
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <tyf1xlmkwc8.fsf@lxplus009.cern.ch>
"Steven E. Harris" <········@raytheon.com> writes:

> If those size/count variables can't be made private,

They can be made private. They _should_ be made private. You should,
however, not _enforce_ that privacy.

There is no language mechanism from preventing users from
dereferencing null pointers either. You simply have to _trust_ your
clients not to pepper their code with *((void*)0). If your clients
_insist_ on doing stupid things, no number of built-in protection
mechanisms will stop them. 

However, if both you and your clients are sensible, then _unenforced_
privacy is the way to go.

Encapsulation is a great idea: access restriction is not.
From: Björn Lindberg
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <hcsbrkrmd3q.fsf@knatte.nada.kth.se>
Jacek Generowicz <················@cern.ch> writes:

> Ari Johnson <·····@hotmail.com> writes:
> 
> > Jacek Generowicz wrote:
> >
> > > access restriction. The whole "privacy" concept seems to be yet
> > > another productivity reduction mechanism built in to C++ (and its
> > > clones ... though I guess C++ didn't actually invent it.)
> > 
> > How does it reduce your productivity?
> 
> By making it difficult (by trying to make it impossible, even) to look
> at (or modify) something you might want/need to see (or modify).
> 
> > Presume that you're working with a large group of programmers.
> > Being able to specify an interface and rely on them not using any
> > internals of your package other than through its interface will
> > increase your productivity by reducing the number of possible bugs
> > at the package boundary.
> 
> The difference is whether you can rely on your colleagues to respect
> the interface or not. If you cannot trust your colleagues to respect
> the interface _unless they have a good reason to work around it_ then
> you have problems far greater than access restriction can cope with.

If you have such a workplace, it would probably not be too difficult
to make the development environment prohibit internal symbol access. I
imagine SLIME could be made not to let double-colon symbols through
for instance. Or allow them, but colour them bright red in the source
code.

The point being it doesn't have to be enforced at the language level.


Bj�rn
From: Pascal Costanza
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <c7v9uu$7r8$2@newsreader2.netcologne.de>
Jacek Generowicz wrote:

> mikel <·····@evins.net> writes:
> 
>>In some languages, class or object boundaries are also encapsulating
>>boundaries; not so in Common Lisp. Common Lisp provides facilities for
>>procedural and data abstraction, but only weak facilities for
>>enncapsulation because, ultimately, you don't want things to be
>>*really* encapsulated; if they were, you couldn't inspect and change
>>them, and interactive Lisp programming is all about inspecting and
>>changing things.
> 
> Am I the last person left on the planet who thinks that
> "encapsulation" is not synonymous with "access restriction" ?

Nope, count me in. ;)

Access restrictions in languages don't buy you anything IMHO.


Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: Alain Picard
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <87oeosk777.fsf@memetrics.com>
Pascal Costanza <········@web.de> writes:

> Jacek Generowicz wrote:
>
>> mikel <·····@evins.net> writes:
>>
>> Am I the last person left on the planet who thinks that
>> "encapsulation" is not synonymous with "access restriction" ?
>
> Nope, count me in. ;)
>
> Access restrictions in languages don't buy you anything IMHO.
>

There's always the good ol' #define private public
:-)
From: Jacek Generowicz
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <tyfu0yjnsy7.fsf@pcepsft001.cern.ch>
Alain Picard <············@memetrics.com> writes:

> There's always the good ol' #define private public
> :-)

My C++ coding guideliens require that it appear at the top of every
file :-)

How do you do it in Java ?
From: Pascal Costanza
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <c834j1$p8g$1@newsreader2.netcologne.de>
Jacek Generowicz wrote:
> Alain Picard <············@memetrics.com> writes:
> 
>>There's always the good ol' #define private public
>>:-)
> 
> My C++ coding guideliens require that it appear at the top of every
> file :-)
> 
> How do you do it in Java ?

It's buried somewhere deep down the debugging API - and of course, you 
need the right access rights, or something. Very tedious.


Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: Damien Kick
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <wtvvl2e6.fsf@email.mot.com>
Alain Picard <············@memetrics.com> writes:

> Pascal Costanza <········@web.de> writes:
> 
> > Jacek Generowicz wrote:
> >
> > Access restrictions in languages don't buy you anything IMHO.
> 
> There's always the good ol' #define private public
> :-)

In C++, one can also cast a pointer to the object to be a pointer to
char, do the necessary pointer arithmatic with the sizes of the
members of the object to point at the private member to which one
wants access, and then recast the 'char*' back to the original type.

    class Squib {
        Foo oof;
        Bar rab;
    }

    Squib* s = new Squib;
    char* p = reinterpret_cast<char*>(s);
    p += sizeof(Foo); // assuming no padding
    Bar* b = reinterpret_cast<Bar*>(p);

This is the longhand form for C++ of using an unexported symbol in
Lisp; it's far more to type but it achieves the same result.
From: Jacek Generowicz
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <tyf3c63p81x.fsf@pcepsft001.cern.ch>
···@zedat.fu-berlin.de (Stefan Ram) writes:

> Jacek Generowicz <················@cern.ch> writes:
> >Am I the last person left on the planet who thinks that
> >"encapsulation" is not synonymous with "access restriction" ?
> 
>   Could you please explain the difference?

Access restriction is making it impossible to access
something. Encapsulation is hiding the implementation details by
providing an interface. Providing an interface does not mean making it
impossible to communicate with the entity without going through the
interface.

Encapsulation is a signpost to the front door. Access restriction
is a big bouncer at the tradesmen's' entrance.
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <xg6pc.3436$Yg.101@fed1read05>
Jacek Generowicz wrote:

> Jacek Generowicz <················@cern.ch> writes:
> 
> 
>>···@zedat.fu-berlin.de (Stefan Ram) writes:
>>
>>
>>>Jacek Generowicz <················@cern.ch> writes:
> 
> 
>>>>"encapsulation" is not synonymous with "access restriction" ?
>>>
>>>  Could you please explain the difference?
> 
> 
> [...]
> 
> 
>>Encapsulation is a signpost to the front door. Access restriction
>>is a big bouncer at the tradesmen's' entrance.
> 
> 
> Encapsulation is closing the bathroom door when you go to have a
> shower. Access restriction is locking the door.
> 
> When you merely close the door you trust that people will respect your
> privacy. When you lock the door you make it more difficult for others
> to catch you playing with yourself; but you also make it more
> difficult for others to rescue you from drowning when, in your
> excitement, you slip and knock yourself unconscious.

I don't have any of these problems in the bathroom.  Maybe I'm not doing 
things the Lisp Way yet. *ducks* ;)
From: Tim Bradshaw
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <fbc0f5d1.0405130922.1897591a@posting.google.com>
mikel <·····@evins.net> wrote in message news:<···················@newssvr27.news.prodigy.com>...
> 
> Common Lisp just doesn't try all that hard to support enncapsulation.

However, if you want it, it's easy to do.  For instance it really is
not that hard to arrange for slots to be very, very hard to get at
without obvious hacks (for instance using the MOP to get all the slot
definition objects, or grovelling around in the internals of the code
that does the private slot stuff to find the appropriate names).

Yes, of course, it's `just a hack using gensymmed slot names', but it
works (and if  you really want to you can probably do something with
the MOP which *isn't* just a hack, but might be horribly slow).

--tim
From: mikel
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <ApOoc.7959$YY7.1782@newssvr27.news.prodigy.com>
Tim Bradshaw wrote:
> mikel <·····@evins.net> wrote in message news:<···················@newssvr27.news.prodigy.com>...
> 
>>Common Lisp just doesn't try all that hard to support enncapsulation.
> 
> 
> However, if you want it, it's easy to do.

True.
From: Joe Marshall
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <ekpotoum.fsf@ccs.neu.edu>
Ari Johnson <·····@hotmail.com> writes:

> Marco Antoniotti wrote:
>> 1 - encapsulation in CL is achieved through packages.
>
> Is this a cry against objects?  

No, it is a consequence of multiple dispatch.  

(defmethod eat ((eater mouth) (eatee cookie)) ...)

Should this be encapsulated within the mouth or the cookie? 
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <3IMoc.126225$Jy3.100135@fed1read03>
Joe Marshall wrote:

> Ari Johnson <·····@hotmail.com> writes:
> 
> 
>>Marco Antoniotti wrote:
>>
>>>1 - encapsulation in CL is achieved through packages.
>>
>>Is this a cry against objects?  
> 
> 
> No, it is a consequence of multiple dispatch.  
> 
> (defmethod eat ((eater mouth) (eatee cookie)) ...)
> 
> Should this be encapsulated within the mouth or the cookie? 

Passive voice is considered bad form in English, the same as I feel it 
is in programming, so your example belongs with the mouth.  An example 
that better makes your point is:

(defmethod add-to-contents ((container container) (mobile mobile)) ...)

Is the mobile entering the container or is the container picking up the 
mobile?  Either answer could be correct, and lack of required 
encapsulation of the method makes it possible not to duplicate code.
From: Gareth McCaughan
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <87wu3f6e0z.fsf@g.mccaughan.ntlworld.com>
Ari Johnson wrote:

> Passive voice is considered bad form in English,

You might want to read that again and think whether you
really (1) believe it and (2) meant to phrase it that way.

-- 
Gareth McCaughan
.sig under construc
From: Paul F. Dietz
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <isidnTh5D4fftzndRVn-vg@dls.net>
Gareth McCaughan wrote:

> Ari Johnson wrote:
> 
>>Passive voice is considered bad form in English,
> 
> You might want to read that again and think whether you
> really (1) believe it and (2) meant to phrase it that way.

Also: "Avoid cliches like the plague."

	Paul
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <V36pc.3224$Yg.904@fed1read05>
Paul F. Dietz wrote:

> Gareth McCaughan wrote:
> 
>> Ari Johnson wrote:
>>
>>> Passive voice is considered bad form in English,
>>
>>
>> You might want to read that again and think whether you
>> really (1) believe it and (2) meant to phrase it that way.
> 
> 
> Also: "Avoid cliches like the plague."

"I'm the most modest man alive."
From: David Steuber
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <87zn8bk356.fsf@david-steuber.com>
Gareth McCaughan <················@pobox.com> writes:

> Ari Johnson wrote:
> 
> > Passive voice is considered bad form in English,
> 
> You might want to read that again and think whether you
> really (1) believe it and (2) meant to phrase it that way.

I don't know about you, but I don't get enough irony in my diet.

-- 
I wouldn't mind the rat race so much if it wasn't for all the damn cats.
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <V56pc.3258$Yg.365@fed1read05>
David Steuber wrote:

> Gareth McCaughan <················@pobox.com> writes:
> 
> 
>>Ari Johnson wrote:
>>
>>
>>>Passive voice is considered bad form in English,
>>
>>You might want to read that again and think whether you
>>really (1) believe it and (2) meant to phrase it that way.
> 
> 
> I don't know about you, but I don't get enough irony in my diet.

I do - my parents took their friend's advice about naming me, except 
they changed one letter so that I wouldn't be called "toast" for short. 
  20 years into life, I found out that the name I did get means 
"breakfast".  And it's not isolated, but rather a theme woven through my 
life.

I really do hate Alanis, though - her definition of irony has hurt the 
irony appreciation abilities of everyone who believes her song.
From: Bruce Hoult
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <bruce-37887C.15530115052004@copper.ipg.tsnz.net>
In article <·················@fed1read05>,
 Ari Johnson <·····@hotmail.com> wrote:
> I really do hate Alanis, though - her definition of irony has hurt the 
> irony appreciation abilities of everyone who believes her song.


<oftopic>
I thought exactly the same as you.  But then I listened to the rest of 
her stuff and ... I'm now sure she's plenty clever enough to know that 
the only irony is at a meta level.

Which doesn't help the listeners who aren't, of course.
</offtopic>

-- Bruce
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <Gsqpc.160474$f_5.151866@lakeread01>
Bruce Hoult wrote:
> In article <·················@fed1read05>,
>  Ari Johnson <·····@hotmail.com> wrote:
> 
>>I really do hate Alanis, though - her definition of irony has hurt the 
>>irony appreciation abilities of everyone who believes her song.
> 
> 
> 
> <oftopic>
> I thought exactly the same as you.  But then I listened to the rest of 
> her stuff and ... I'm now sure she's plenty clever enough to know that 
> the only irony is at a meta level.
> 
> Which doesn't help the listeners who aren't, of course.

I also don't like her singing voice or style of music, so I never 
bothered to find that out.  As you've agreed, my statement stands: she's 
hurt the ability of 99% of better of her listeners to understand or 
appreciate irony.

> </offtopic>
From: Bruce Hoult
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <bruce-E59760.11022916052004@copper.ipg.tsnz.net>
In article <·······················@lakeread01>,
 Ari Johnson <·····@hotmail.com> wrote:

> Bruce Hoult wrote:
> > In article <·················@fed1read05>,
> >  Ari Johnson <·····@hotmail.com> wrote:
> > 
> >>I really do hate Alanis, though - her definition of irony has hurt the 
> >>irony appreciation abilities of everyone who believes her song.
> > 
> > 
> > 
> > <oftopic>
> > I thought exactly the same as you.  But then I listened to the rest of 
> > her stuff and ... I'm now sure she's plenty clever enough to know that 
> > the only irony is at a meta level.
> > 
> > Which doesn't help the listeners who aren't, of course.
> 
> I also don't like her singing voice or style of music, so I never 
> bothered to find that out.  As you've agreed, my statement stands: she's 
> hurt the ability of 99% of better of her listeners to understand or 
> appreciate irony.
> 
> > </offtopic>

<ontopic>
Just as Lots of Insanely Stupid Parentheses cause more than 99% of 
potential Lisp programmers to never understand or appreciate the really 
beautiful and clever parts, don't you think?  You and I aren't bothered, 
but many people are.
</ontopic>

-- Bruce
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <j36pc.3214$Yg.656@fed1read05>
Gareth McCaughan wrote:

> Ari Johnson wrote:
> 
> 
>>Passive voice is considered bad form in English,
> 
> 
> You might want to read that again and think whether you
> really (1) believe it and (2) meant to phrase it that way.

1. Depends on the writing.  Technical documentation, it's more often 
good form than it is bad.

2. Yes, I absolutely did.  Glad someone caught it. :)
From: Joe Marshall
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <ad0bgqbf.fsf@ccs.neu.edu>
Ari Johnson <·····@hotmail.com> writes:

> Joe Marshall wrote:
>
>> Ari Johnson <·····@hotmail.com> writes:
>>
>>>Marco Antoniotti wrote:
>>>
>>>>1 - encapsulation in CL is achieved through packages.
>>>
>>> Is this a cry against objects?
>> No, it is a consequence of multiple dispatch.  (defmethod eat
>> ((eater mouth) (eatee cookie)) ...)
>> Should this be encapsulated within the mouth or the cookie?
>
> Passive voice is considered bad form in English, the same as I feel it
> is in programming, so your example belongs with the mouth.  

I didn't know Strunk and White wrote software.
From: Karl A. Krueger
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <c7vus1$afr$1@baldur.whoi.edu>
Joe Marshall <···@ccs.neu.edu> wrote:
> Ari Johnson <·····@hotmail.com> writes:
>> Marco Antoniotti wrote:
>>> 1 - encapsulation in CL is achieved through packages.
>>
>> Is this a cry against objects?  
> 
> No, it is a consequence of multiple dispatch.  
> 
> (defmethod eat ((eater mouth) (eatee cookie)) ...)
> 
> Should this be encapsulated within the mouth or the cookie? 

The cookie should be encapsulated within the mouth.  Otherwise you get
crumbs everywhere, and nobody wants to see you chew anyhow.  Violating
encapsulation is bad table manners.

-- 
Karl A. Krueger <········@example.edu>
Woods Hole Oceanographic Institution
Email address is spamtrapped.  s/example/whoi/
"Outlook not so good." -- Magic 8-Ball Software Reviews
From: Marco Antoniotti
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <jdroc.198$a5.55999@typhoon.nyu.edu>
Marco Antoniotti wrote:

> 
> 
> Ari Johnson wrote:
> 
>> A nifty feature of Ruby and C# is property getter/setter methods.  
>> This lets you do, for example, the following:
>>
>> --C# code--
>> class root {
>>   protected string _name;
>>   public string name {
>>     get { return _name; }
>>     set { _name = name; }
>>   }
>> };
>>
>> class leaf : root {
>>   private bool valid_name(string name) {
>>     return false;
>>   }
>>   new public string name {
>>     get { return _name; }
>>     set { if(valid_name(name)) _name = name; }
>>   }
>> };
>> -----------
>>
>> The specific feature I'm looking at is the property setter for name in 
>> the leaf class.  Does CLOS offer this functionality?
> 
> 
> This question is obviously better rephrased as "what functionality of 
> CLOS am I missing in C#, C++, Java and SLDJ (Scripting Language Du Jour)"?
> 
> 
> 
> 
>   When I do the
> 
>> following, I want to be able to redefine the setter for the name slot 
>> in leaf.  Can this be done?  What's considered the best way?
>>
>> --Lisp Code--
>> (defclass root ()
>>   ((name :accessor name :initarg :name)))
>> (defclass leaf (root) ())
>> -------------
>>
>> For a simple example, let's say I want the following to occur:
>>
>> * (setf a-root (make-instance 'root :name "The Root"))
>> #<ROOT ...>
>> * (setf a-leaf (make-instance 'leaf :name "The Leaf"))
>> #<LEAF ...>
>> * (setf (name a-root) "A Root")
>> "A Root"
>> * (valid-name "Bob")
>> NIL
>> * (valid-name "A Leaf")
>> T
>> * (setf (name a-leaf) "Bob")
>> NIL
>> * (name a-leaf)
>> "The Leaf"
>> * (setf (name a-leaf) "A Leaf")
>> "A Leaf"
>> * (name a-leaf)
>> "A Leaf"
>>
>> Does this make sense?  How can it be done?  Thanks!
> 
> 
> 
> (defclass root ()
>   ((name :accessor name :initarg :name)))
> 
> (defclass leaf (root)
>   ())
> 
> (defmethod valid-name-p ((l leaf) (n string)) nil)
> 
> (defmethod (setf name) :around (n (l leaf))
>    (when (valid-name-p n) (call-next-method)))
> 
> This is what you wanted.  You can vary this theme.

I forgot.  (And I made a mistake in the previous code: the above is now 
correct)

Suppose you want a special leaf.

(defclass fig-leaf (leaf) ()

(defmethod valid-name-p ((f fig-leaf) (n string))
    (string-equal "Large enough to cover you-know-what" n))

Now you have what you want.  But suppose you have a specific instance of 
a FIG-LEAF

(defvar *naughty-fig-leaf* (make-instance 'fig-leaf))

(defmethod valid-name-p ((nf (eql *naughty-fig-leaf*)) (n string))
    (string-equal "Small"))


You now have redefined the method on a specific instance.

Cheers

Marco
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <NSroc.119725$Jy3.109291@fed1read03>
Marco Antoniotti wrote:

> 
> 
> Marco Antoniotti wrote:
> 
>>
>>
>> Ari Johnson wrote:
>>
>>> A nifty feature of Ruby and C# is property getter/setter methods.  
>>> This lets you do, for example, the following:
>>>
>>> --C# code--
>>> class root {
>>>   protected string _name;
>>>   public string name {
>>>     get { return _name; }
>>>     set { _name = name; }
>>>   }
>>> };
>>>
>>> class leaf : root {
>>>   private bool valid_name(string name) {
>>>     return false;
>>>   }
>>>   new public string name {
>>>     get { return _name; }
>>>     set { if(valid_name(name)) _name = name; }
>>>   }
>>> };
>>> -----------
>>>
>>> The specific feature I'm looking at is the property setter for name 
>>> in the leaf class.  Does CLOS offer this functionality?
>>
>>
>>
>> This question is obviously better rephrased as "what functionality of 
>> CLOS am I missing in C#, C++, Java and SLDJ (Scripting Language Du 
>> Jour)"?
>>
>>
>>
>>
>>   When I do the
>>
>>> following, I want to be able to redefine the setter for the name slot 
>>> in leaf.  Can this be done?  What's considered the best way?
>>>
>>> --Lisp Code--
>>> (defclass root ()
>>>   ((name :accessor name :initarg :name)))
>>> (defclass leaf (root) ())
>>> -------------
>>>
>>> For a simple example, let's say I want the following to occur:
>>>
>>> * (setf a-root (make-instance 'root :name "The Root"))
>>> #<ROOT ...>
>>> * (setf a-leaf (make-instance 'leaf :name "The Leaf"))
>>> #<LEAF ...>
>>> * (setf (name a-root) "A Root")
>>> "A Root"
>>> * (valid-name "Bob")
>>> NIL
>>> * (valid-name "A Leaf")
>>> T
>>> * (setf (name a-leaf) "Bob")
>>> NIL
>>> * (name a-leaf)
>>> "The Leaf"
>>> * (setf (name a-leaf) "A Leaf")
>>> "A Leaf"
>>> * (name a-leaf)
>>> "A Leaf"
>>>
>>> Does this make sense?  How can it be done?  Thanks!
>>
>>
>>
>>
>> (defclass root ()
>>   ((name :accessor name :initarg :name)))
>>
>> (defclass leaf (root)
>>   ())
>>
>> (defmethod valid-name-p ((l leaf) (n string)) nil)
>>
>> (defmethod (setf name) :around (n (l leaf))
>>    (when (valid-name-p n) (call-next-method)))
>>
>> This is what you wanted.  You can vary this theme.
> 
> 
> I forgot.  (And I made a mistake in the previous code: the above is now 
> correct)

Are you sure?  It looks to me like valid-name-p takes two arguments, but 
you only give it one.

> 
> Suppose you want a special leaf.
> 
> (defclass fig-leaf (leaf) ()
> 
> (defmethod valid-name-p ((f fig-leaf) (n string))
>    (string-equal "Large enough to cover you-know-what" n))
> 
> Now you have what you want.  But suppose you have a specific instance of 
> a FIG-LEAF
> 
> (defvar *naughty-fig-leaf* (make-instance 'fig-leaf))

This brings up another question - is there an analog to constructors 
(destructors don't make much sense but would be trivial) that could help 
me ensure that the original make-instance makes a valid instance?  In 
this case, it does not, as (valid-name-p *naughty-fig-leaf* (name 
*naughty-fig-leaf*)) => NIL

> (defmethod valid-name-p ((nf (eql *naughty-fig-leaf*)) (n string))
>    (string-equal "Small"))
> 
> 
> You now have redefined the method on a specific instance.

Indeed, I knew this was possible.  I'm sure eventually I'll come up with 
an excuse to use it, but for now I'm becoming conversant in the basics 
and can't imagine a lot of legitimate use for this functionality. :)

> Cheers

And to you.
From: Marco Antoniotti
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <SKsoc.201$a5.56080@typhoon.nyu.edu>
Ari Johnson wrote:

>>>
>>>
>>>
>>> (defclass root ()
>>>   ((name :accessor name :initarg :name)))
>>>
>>> (defclass leaf (root)
>>>   ())
>>>
>>> (defmethod valid-name-p ((l leaf) (n string)) nil)
>>>
>>> (defmethod (setf name) :around (n (l leaf))
>>>    (when (valid-name-p n) (call-next-method)))
>>>
>>> This is what you wanted.  You can vary this theme.
>>
>>
>>
>> I forgot.  (And I made a mistake in the previous code: the above is 
>> now correct)
> 
> 
> Are you sure?  It looks to me like valid-name-p takes two arguments, but 
> you only give it one.

Yes.  My original post had only one argument (wrong).  My second one 
corrected it.  Se above.

>>
>> Suppose you want a special leaf.
>>
>> (defclass fig-leaf (leaf) ()
>>
>> (defmethod valid-name-p ((f fig-leaf) (n string))
>>    (string-equal "Large enough to cover you-know-what" n))
>>
>> Now you have what you want.  But suppose you have a specific instance 
>> of a FIG-LEAF
>>
>> (defvar *naughty-fig-leaf* (make-instance 'fig-leaf))
> 
> 
> This brings up another question - is there an analog to constructors 
> (destructors don't make much sense but would be trivial) that could help 
> me ensure that the original make-instance makes a valid instance?  In 
> this case, it does not, as (valid-name-p *naughty-fig-leaf* (name 
> *naughty-fig-leaf*)) => NIL
> 
>> (defmethod valid-name-p ((nf (eql *naughty-fig-leaf*)) (n string))
>>    (string-equal "Small"))

Sorry

	(defvar *naughty-fig-leaf*
             (make-instance 'fig-leaf :name "Small"))

That is what the :initarg is for.

Now, I am not sure what you mean by "ensure that the original 
make-instance makes a valid instance".  If you mean: I want to be sure 
that my instance has a valid name, then you would add before calling 
MAKE-INSTANCE

(defmethod initialize-instance :before ((fl fig-leaf)
                                         &key (name "")
                                         &allow-other-keys)
    (unless (string-equal name  "Large enough to cover you-know-what")
       (cerror "Continue and make the instance."
               "Invalid name ~S." name)))

This way you are programming the instance creation machinery at the 
right point.


Cheers
--
Marco
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <ToCoc.125387$Jy3.56873@fed1read03>
Marco Antoniotti wrote:
>>>> (defmethod valid-name-p ((l leaf) (n string)) nil)
>>>>
>>>> (defmethod (setf name) :around (n (l leaf))
>>>>    (when (valid-name-p n) (call-next-method)))
> Yes.  My original post had only one argument (wrong).  My second one 
> corrected it.  Se above.

Won't valid-name-p require two arguments, and the call (valid-name-p n) 
only give it one?

> Now, I am not sure what you mean by "ensure that the original 
> make-instance makes a valid instance".  If you mean: I want to be sure 
> that my instance has a valid name, then you would add before calling 
> MAKE-INSTANCE
> 
> (defmethod initialize-instance :before ((fl fig-leaf)
>                                         &key (name "")
>                                         &allow-other-keys)
>    (unless (string-equal name  "Large enough to cover you-know-what")
>       (cerror "Continue and make the instance."
>               "Invalid name ~S." name)))
> 
> This way you are programming the instance creation machinery at the 
> right point.

That was the correct answer, thanks. :)
From: Thomas F. Burdick
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <xcvvfj1xnxn.fsf@famine.OCF.Berkeley.EDU>
Ari Johnson <·····@hotmail.com> writes:

> This brings up another question - is there an analog to constructors 
> (destructors don't make much sense but would be trivial) that could help 
> me ensure that the original make-instance makes a valid instance?  In 
> this case, it does not, as (valid-name-p *naughty-fig-leaf* (name 
> *naughty-fig-leaf*)) => NIL

Things like this are generally done with methods (usually :before or
:after) on INITIALIZE-INSTANCE.  It's more powerful than C++-style
constructors, too.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <lEzoc.124574$Jy3.118221@fed1read03>
Thomas F. Burdick wrote:

> Ari Johnson <·····@hotmail.com> writes:
> 
> 
>>This brings up another question - is there an analog to constructors 
>>(destructors don't make much sense but would be trivial) that could help 
>>me ensure that the original make-instance makes a valid instance?  In 
>>this case, it does not, as (valid-name-p *naughty-fig-leaf* (name 
>>*naughty-fig-leaf*)) => NIL
> 
> 
> Things like this are generally done with methods (usually :before or
> :after) on INITIALIZE-INSTANCE.  It's more powerful than C++-style
> constructors, too.

I didn't know about initialize-instance, and I agree with your final 
statement now that I do.
From: Thomas A. Russ
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <ymi7jvhs63j.fsf@sevak.isi.edu>
Marco Antoniotti <·······@cs.nyu.edu> writes:


> (defmethod (setf name) :around (n (l leaf))
>     (when (valid-name-p n) (call-next-method)))
> 
> This is what you wanted.  You can vary this theme.

Now, why are all of these setf checker methods being defined as :around
methods instead of just ordinary methods with the same definition?

I guess one reason is to make it so that they will be executed even if a
subclass of LEAF defines its own (SETF NAME) method?

I suppose that one should really make the choice between an :around or
normal method based on whether this should be an enforced method on all
subclasses or just a default inherited method for the subclasses, right?


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Barry Margolin
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <barmar-ED3473.20473812052004@comcast.ash.giganews.com>
In article <···············@sevak.isi.edu>,
 ···@sevak.isi.edu (Thomas A. Russ) wrote:

> Marco Antoniotti <·······@cs.nyu.edu> writes:
> 
> 
> > (defmethod (setf name) :around (n (l leaf))
> >     (when (valid-name-p n) (call-next-method)))
> > 
> > This is what you wanted.  You can vary this theme.
> 
> Now, why are all of these setf checker methods being defined as :around
> methods instead of just ordinary methods with the same definition?

Because you want this checking to occur before :BEFORE methods are run.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Joe Marshall
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <wu3gs8gl.fsf@ccs.neu.edu>
···@sevak.isi.edu (Thomas A. Russ) writes:

> Marco Antoniotti <·······@cs.nyu.edu> writes:
>
>
>> (defmethod (setf name) :around (n (l leaf))
>>     (when (valid-name-p n) (call-next-method)))
>> 
>> This is what you wanted.  You can vary this theme.
>
> Now, why are all of these setf checker methods being defined as :around
> methods instead of just ordinary methods with the same definition?

I think they should be ordinary methods.

> I suppose that one should really make the choice between an :around or
> normal method based on whether this should be an enforced method on all
> subclasses or just a default inherited method for the subclasses, right?

It depends on the data model.  Suppose that leaf-nodes were valid if
they had the word `leaf' somewhere in their name.

(defun valid-name-p (x) (search "leaf" x))

And now we subclass leaf nodes:

(defclass green-leaf-node (leaf-node) ())

(defmethod (setf name) (new-name (object green-leaf-node))
  (call-next-method
     (concatenate 'string "A green leaf named " new-name)
     object))

In this case, we probably want to do the validity check on what is
going to be stored, not what was passed in originally.
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <lQMoc.126229$Jy3.45327@fed1read03>
Joe Marshall wrote:

> ···@sevak.isi.edu (Thomas A. Russ) writes:
> 
> 
>>Marco Antoniotti <·······@cs.nyu.edu> writes:
>>
>>
>>
>>>(defmethod (setf name) :around (n (l leaf))
>>>    (when (valid-name-p n) (call-next-method)))
>>>
>>>This is what you wanted.  You can vary this theme.
>>
>>Now, why are all of these setf checker methods being defined as :around
>>methods instead of just ordinary methods with the same definition?
> 
> 
> I think they should be ordinary methods.
> 
> 
>>I suppose that one should really make the choice between an :around or
>>normal method based on whether this should be an enforced method on all
>>subclasses or just a default inherited method for the subclasses, right?
> 
> 
> It depends on the data model.  Suppose that leaf-nodes were valid if
> they had the word `leaf' somewhere in their name.
> 
> (defun valid-name-p (x) (search "leaf" x))
> 
> And now we subclass leaf nodes:
> 
> (defclass green-leaf-node (leaf-node) ())
> 
> (defmethod (setf name) (new-name (object green-leaf-node))
>   (call-next-method
>      (concatenate 'string "A green leaf named " new-name)
>      object))
> 
> In this case, we probably want to do the validity check on what is
> going to be stored, not what was passed in originally.

Good point.
From: jan
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <uzn8ahb53.fsf@iprimus.com.au>
Joe Marshall <···@ccs.neu.edu> writes:

>>> (defmethod (setf name) :around (n (l leaf))
>>>     (when (valid-name-p n) (call-next-method)))
>>
>> Now, why are all of these setf checker methods being defined as :around
>> methods instead of just ordinary methods with the same definition?
> 
> I think they should be ordinary methods.
> 
> It depends on the data model.  Suppose that leaf-nodes were valid if
> they had the word `leaf' somewhere in their name.
> 
> (defun valid-name-p (x) (search "leaf" x))
> 
> And now we subclass leaf nodes:
> 
> (defclass green-leaf-node (leaf-node) ())
> 
> (defmethod (setf name) (new-name (object green-leaf-node))
>   (call-next-method
>      (concatenate 'string "A green leaf named " new-name)
>      object))
> 
> In this case, we probably want to do the validity check on what is
> going to be stored, not what was passed in originally.

why not just make it an around method aswell?

(defmethod (setf name) :around (new-name (object green-leaf-node))
  (call-next-method
        (concatenate 'string "A green leaf named " new-name)
        object))

-- 
jan
From: Joe Marshall
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <65azgq4u.fsf@ccs.neu.edu>
> Joe Marshall <···@ccs.neu.edu> writes:
>> 
>> In this case, we probably want to do the validity check on what is
>> going to be stored, not what was passed in originally.
>


> jan <······@iprimus.com.au> writes:
> why not just make it an around method aswell?
>
> (defmethod (setf name) :around (new-name (object green-leaf-node))
>   (call-next-method
>         (concatenate 'string "A green leaf named " new-name)
>         object))

This would defeat overrides in further subclasses.

(Of course you could put *them* in :around methods, too, but
eventually everything will be in an around method and you won't be
able to use :around methods for the kind of thing you'd really like an
around method for.)
From: Paolo Amoroso
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <87y8nxe9uy.fsf@plato.moon.paoloamoroso.it>
Marco Antoniotti <·······@cs.nyu.edu> writes:

> This question is obviously better rephrased as "what functionality of
> CLOS am I missing in C#, C++, Java and SLDJ (Scripting Language Du
> Jour)"?

Lisp.


Paolo
-- 
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
Recommended Common Lisp libraries/tools (Google for info on each):
- ASDF/ASDF-INSTALL: system building/installation
- CL-PPCRE: regular expressions
- UFFI: Foreign Function Interface
From: Jacek Generowicz
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <tyf7jvhrjyc.fsf@pcepsft001.cern.ch>
Ari Johnson <·····@hotmail.com> writes:

> When I do the following, I want to be able to redefine the setter
> for the name slot in leaf.  Can this be done?  What's considered the
> best way?
> 
> 
> --Lisp Code--
> (defclass root ()
>    ((name :accessor name :initarg :name)))

Rhetorical question: What is the effect of ":accessor name" in the above ?

[hint: try 

  (list #'name #'(setf name))

in a fresh Lisp image before evaluating the above form, then try it
again after evaluating the form.]

Hopefully you see that the accessors are just methods on a generic
function, created for you by _defclass_. _defclass_ creates pretty
boring methods (it does the default thing: get or set the slot
value). If you want your method to be more exciting, write it yourself
explicitly:

  (defmethod name ((leaf leaf)) ... )

You could write ALL your accessors explicitly, it's just that usually
the accessors don't do anything special, so defclass creates default
ones for you, if you ask it to.
From: Hannah Schroeter
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <c7t36m$ld3$1@c3po.use.schlund.de>
Hello!

Jacek Generowicz  <················@cern.ch> wrote:
>[...]

>value). If you want your method to be more exciting, write it yourself
>explicitly:

>  (defmethod name ((leaf leaf)) ... )

>You could write ALL your accessors explicitly, it's just that usually
>the accessors don't do anything special, so defclass creates default
>ones for you, if you ask it to.

And because of the wonders of method combination, you don't have to
define everything yourself.

(defmethod (setf name) :before (new-name ((leaf leaf)))
  (unless (name-ok new-name)
    (error "tried to set an invalid name")))

Kind regards,

Hannah.
From: Jacek Generowicz
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <tyf3c65rgsx.fsf@pcepsft001.cern.ch>
······@schlund.de (Hannah Schroeter) writes:

> (defmethod (setf name) :before (new-name ((leaf leaf)))
                                           ^           ^
Lost In Superfluous Parentheses ?  :-)
From: Hannah Schroeter
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <c7t4sl$dsm$1@c3po.use.schlund.de>
Hello!

Jacek Generowicz  <················@cern.ch> wrote:
>······@schlund.de (Hannah Schroeter) writes:

>> (defmethod (setf name) :before (new-name ((leaf leaf)))
>                                           ^           ^
>Lost In Superfluous Parentheses ?  :-)

Yes, sorry ;-)

Kind regards,

Hannah.
From: Steve Long
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <BCE01E18.62DA%sal6741@hotmail.com>
On 05/12/2004 3:58 AM, in article ···············@pcepsft001.cern.ch, "Jacek
Generowicz" <················@cern.ch> wrote:

> Ari Johnson <·····@hotmail.com> writes:
> 
>> When I do the following, I want to be able to redefine the setter
>> for the name slot in leaf.  Can this be done?  What's considered the
>> best way?
>> 
>> 
>> --Lisp Code--
>> (defclass root ()
>>    ((name :accessor name :initarg :name)))
> 
> Rhetorical question: What is the effect of ":accessor name" in the above ?
> 
> [hint: try 
> 
> (list #'name #'(setf name))
> 
> in a fresh Lisp image before evaluating the above form, then try it
> again after evaluating the form.]
> 
> Hopefully you see that the accessors are just methods on a generic
> function, created for you by _defclass_. _defclass_ creates pretty
> boring methods (it does the default thing: get or set the slot
> value). If you want your method to be more exciting, write it yourself
> explicitly:
> 
> (defmethod name ((leaf leaf)) ... )
> 
> You could write ALL your accessors explicitly, it's just that usually
> the accessors don't do anything special, so defclass creates default
> ones for you, if you ask it to.
> 


Yes, this is handy; when I've got interdependencies between slots, I take
advantage of the lazy nature of standard-class slot binding. A simple
example:

(defclass obj () ())

(defmethod eval-iv ((obj obj) sym function)
  (if (slot-boundp obj sym)
      (slot-value obj sym)
    (setf (slot-value obj sym) (funcall function obj))))

(defclass box (obj)
  ((L :initarg :length :reader length-of)
   (W  :initarg :width :reader width-of)
   (H :initarg :height :reader height-of)
   (V)))

(defmethod volume-of ((self box))
  (eval-iv 
   obj 
   'volume 
   #'(lambda(self)(* (length-of self) (width-of self) (height-of self)))))


There are fancier ways of doing this that involve using a macro to define
the class and methods together and syntax for short-cutting methods like
EVAL-IV. This is what I really like about Lisp.

sl
From: Kenny Tilton
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <8nroc.62812$Nn4.15504205@twister.nyc.rr.com>
Ari Johnson wrote:
> A nifty feature of Ruby and C# is property getter/setter methods.  This 
> lets you do, for example, the following:
> 
> --C# code--
> class root {
>   protected string _name;
>   public string name {
>     get { return _name; }
>     set { _name = name; }
>   }
> };
> 
> class leaf : root {
>   private bool valid_name(string name) {
>     return false;
>   }
>   new public string name {
>     get { return _name; }
>     set { if(valid_name(name)) _name = name; }
>   }
> };
> -----------
> 
> The specific feature I'm looking at is the property setter for name in 
> the leaf class.  Does CLOS offer this functionality?  When I do the 
> following, I want to be able to redefine the setter for the name slot in 
> leaf.  Can this be done?  What's considered the best way?
> 
> --Lisp Code--
> (defclass root ()
>   ((name :accessor name :initarg :name)))
> (defclass leaf (root) ())
> -------------
> 
> For a simple example, let's say I want the following to occur:
> 
> * (setf a-root (make-instance 'root :name "The Root"))
> #<ROOT ...>
> * (setf a-leaf (make-instance 'leaf :name "The Leaf"))
> #<LEAF ...>
> * (setf (name a-root) "A Root")
> "A Root"
> * (valid-name "Bob")
> NIL
> * (valid-name "A Leaf")
> T
> * (setf (name a-leaf) "Bob")
> NIL

I am just a humble application programmer, but I think this breaks SETF. 
SETF is supposed to return "the multiple values returned by the storing 
form for the last place".

The "storing" qualifier has me puzzled. Possibly that means "Bob" should 
be returned. Me, I think the unchanged value of the place should be 
returned, namely "A Leaf". But not nil.

CL language lawyers?

kenny

-- 
Home? http://tilton-technology.com
Cells? http://www.common-lisp.net/project/cells/
Cello? http://www.common-lisp.net/project/cello/
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
Your Project Here! http://alu.cliki.net/Industry%20Application
From: Nils Gösche
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <87brktbh23.fsf@darkstar.cartan.de>
Kenny Tilton <·······@nyc.rr.com> writes:

> Ari Johnson wrote:

> > * (setf (name a-leaf) "Bob")
> > NIL

> I am just a humble application programmer, but I think this breaks
> SETF. SETF is supposed to return "the multiple values returned by
> the storing form for the last place".
> 
> The "storing" qualifier has me puzzled. Possibly that means "Bob"
> should be returned. Me, I think the unchanged value of the place
> should be returned, namely "A Leaf". But not nil.

I think "storing form" is a reference to 5.1.1.2.  See if it helps :-)

Regards,
-- 
Nils G�sche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x7E4651AD
From: Nils Gösche
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <877jvhbgu7.fsf@darkstar.cartan.de>
I wrote:

> Kenny Tilton <·······@nyc.rr.com> writes:
> 
> > Ari Johnson wrote:
> 
> > > * (setf (name a-leaf) "Bob")
> > > NIL
> 
> > I am just a humble application programmer, but I think this breaks
> > SETF. SETF is supposed to return "the multiple values returned by
> > the storing form for the last place".
> > 
> > The "storing" qualifier has me puzzled. Possibly that means "Bob"
> > should be returned. Me, I think the unchanged value of the place
> > should be returned, namely "A Leaf". But not nil.
> 
> I think "storing form" is a reference to 5.1.1.2.  See if it helps :-)

Ah, and 5.1.2.9 says

# A function named (setf f) must return its first argument as its only
# value in order to preserve the semantics of setf.

Which I /think/ is relevant here...

Regards,
-- 
Nils G�sche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x7E4651AD
From: Kenny Tilton
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <qYvoc.62819$Nn4.15548839@twister.nyc.rr.com>
Nils G�sche wrote:

> I wrote:
> 
> 
>>Kenny Tilton <·······@nyc.rr.com> writes:
>>
>>
>>>Ari Johnson wrote:
>>
>>>>* (setf (name a-leaf) "Bob")
>>>>NIL
>>
>>>I am just a humble application programmer, but I think this breaks
>>>SETF. SETF is supposed to return "the multiple values returned by
>>>the storing form for the last place".
>>>
>>>The "storing" qualifier has me puzzled. Possibly that means "Bob"
>>>should be returned. Me, I think the unchanged value of the place
>>>should be returned, namely "A Leaf". But not nil.
>>
>>I think "storing form" is a reference to 5.1.1.2.  See if it helps :-)

Impenetrable!

> 
> 
> Ah, and 5.1.2.9 says
> 
> # A function named (setf f) must return its first argument as its only
> # value in order to preserve the semantics of setf.

Now we're talking. So:

  (list (setf (name a-leaf) "Bob") (name a-leaf))
must => ("Bob" "A leaf")

...which reinforces my other thought, which is that silently defeating 
the setf is Deeply Wrong.

kenny

-- 
Home? http://tilton-technology.com
Cells? http://www.common-lisp.net/project/cells/
Cello? http://www.common-lisp.net/project/cello/
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
Your Project Here! http://alu.cliki.net/Industry%20Application
From: Peter Seibel
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <m3k6zhwctv.fsf@javamonkey.com>
Kenny Tilton <·······@nyc.rr.com> writes:

> Nils G�sche wrote:
>
>> I wrote:
>>
>>>Kenny Tilton <·······@nyc.rr.com> writes:
>>>
>>>
>>>>Ari Johnson wrote:
>>>
>>>>>* (setf (name a-leaf) "Bob")
>>>>>NIL
>>>
>>>>I am just a humble application programmer, but I think this breaks
>>>>SETF. SETF is supposed to return "the multiple values returned by
>>>>the storing form for the last place".
>>>>
>>>>The "storing" qualifier has me puzzled. Possibly that means "Bob"
>>>>should be returned. Me, I think the unchanged value of the place
>>>>should be returned, namely "A Leaf". But not nil.
>>>
>>>I think "storing form" is a reference to 5.1.1.2.  See if it helps :-)
>
> Impenetrable!
>
>> Ah, and 5.1.2.9 says
>> # A function named (setf f) must return its first argument as its
>> only
>> # value in order to preserve the semantics of setf.
>
> Now we're talking. So:
>
>   (list (setf (name a-leaf) "Bob") (name a-leaf))
> must => ("Bob" "A leaf")
>
> ...which reinforces my other thought, which is that silently defeating
> the setf is Deeply Wrong.

I'm with you, Kenny. Though it does seem like it would be acceptable
to write:

   (defmethod (setf name) :around (name (leaf leaf))
     (if (valid-name name)
       (call-next-method)
       (error 'class-invariant-violated-error
              "Can't set NAME to ~a on a LEAF" name)))

Or maybe better:

    (defmethod (setf name) :before (name (leaf leaf))
      (unless (valid-name name)
       (error 'class-invariant-violated-error
              "Can't set NAME to ~a on a LEAF" name)))

In this case SETF will never return NIL because there's no way out of
the ERROR except for some handler (or the user in the debgger) to
unwind the stack. And then we're not in the SETF function anymore so
we don't have to fulfill it's contract.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Bruce Hoult
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <bruce-B4C245.19451612052004@copper.ipg.tsnz.net>
In article <······················@fed1read03>,
 Ari Johnson <·····@hotmail.com> wrote:

> A nifty feature of Ruby and C# is property getter/setter methods.  This 
> lets you do, for example, the following:

And Common Lisp and Dylan too.


> --C# code--
> class root {
>    protected string _name;
>    public string name {
>      get { return _name; }
>      set { _name = name; }
>    }
> };
> 
> class leaf : root {
>    private bool valid_name(string name) {
>      return false;
>    }
>    new public string name {
>      get { return _name; }
>      set { if(valid_name(name)) _name = name; }
>    }
> };
> -----------

I'm sure you'll get plenty of CL replies, but for information purposes 
here's how you do it in Dylan.  The key is the use of next-method to 
call the automatically generated (unlike in C#) setter for <root>.  When 
caleld with no arguments, next-method() passes on the original arguments 
unchanged.  You could also modify the arguments and pass them to 
next-method() explicitly.


-------------
module: accessors

define class <root> (<object>)
  slot name :: <string>, init-keyword: name:;
end;

define class <leaf> (<root>) end;

define method name-setter(newName :: <string>, it :: <leaf>)
  valid-name(newName) & next-method();
end;

define function valid-name(name)
  name = "A Leaf";
end;

begin
  let a-root = make(<root>, name: "The Root");
  let a-leaf = make(<leaf>, name: "The Leaf");
  a-root.name := "A Root";
  format-out("a-root=%s\n", a-root.name);

  a-leaf.name := "Bob";
  format-out("a-leaf=%s  (could be Bob)\n", a-leaf.name);

  a-leaf.name := "A Leaf";
  format-out("a-leaf=%s  (could be A Leaf)\n", a-leaf.name);
end;
-------------
iMac:~/programs/dylan/accessors$ ./accessors 
a-root=A Root
a-leaf=The Leaf  (could be Bob)
a-leaf=A Leaf  (could be A Leaf)
-------------
From: Joe Marshall
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <n04ctp4q.fsf@ccs.neu.edu>
Ari Johnson <·····@hotmail.com> writes:

> A nifty feature of Ruby and C# is property getter/setter methods.

Um, no.  `Properties' are an artifact of lack of multiple
inheritance.  The kludge of implementing `interfaces' only allows you
to inherit methods, so to fake the inheritance of slots you create
`getter' and `setter' methods so that it almost looks as if you
inherited a field. 

> The specific feature I'm looking at is the property setter for name in
> the leaf class.  Does CLOS offer this functionality?  

The answer to that question is almost always `yes', although it might
have the `if you use the MOP' appended to it.


> When I do the following, I want to be able to redefine the setter
> for the name slot in leaf.  Can this be done?  

Yes.

> What's considered the best way?

Here's what I'd write, but I don't know what people would consider is
the best way.

> --Lisp Code--
> (defclass root ()
>    ((name :accessor name :initarg :name)))
> (defclass leaf (root) ())

(defmethod (setf name) (new-name (object leaf))
  (when (valid-name-p new-name)
    (call-next-method)))
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <UFMoc.126224$Jy3.97008@fed1read03>
Joe Marshall wrote:

> Ari Johnson <·····@hotmail.com> writes:
> 
> 
>>A nifty feature of Ruby and C# is property getter/setter methods.
> 
> 
> Um, no.  `Properties' are an artifact of lack of multiple
> inheritance.  The kludge of implementing `interfaces' only allows you
> to inherit methods, so to fake the inheritance of slots you create
> `getter' and `setter' methods so that it almost looks as if you
> inherited a field. 

I disagree.  I may find that the primary shortcoming of both of the 
languages I cited is lack of multiple inheritance, but their 
'properties' are more syntactic sugar than a result of that shortcoming 
- the end justifies the means, and so forth.

>>--Lisp Code--
>>(defclass root ()
>>   ((name :accessor name :initarg :name)))
>>(defclass leaf (root) ())
> 
> 
> (defmethod (setf name) (new-name (object leaf))
>   (when (valid-name-p new-name)
>     (call-next-method)))

I think we decided that :before or :around is a better choice, if I want 
to prevent subclasses of leaf from overriding my restriction.
From: Joe Marshall
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <hduks0e4.fsf@ccs.neu.edu>
Ari Johnson <·····@hotmail.com> writes:

> Joe Marshall wrote:
>
>> Ari Johnson <·····@hotmail.com> writes:
>>
>>>A nifty feature of Ruby and C# is property getter/setter methods.
>> Um, no.  `Properties' are an artifact of lack of multiple
>> inheritance.  The kludge of implementing `interfaces' only allows you
>> to inherit methods, so to fake the inheritance of slots you create
>> `getter' and `setter' methods so that it almost looks as if you
>> inherited a field.
>
> I disagree.  I may find that the primary shortcoming of both of the
> languages I cited is lack of multiple inheritance, but their
> 'properties' are more syntactic sugar than a result of that
> shortcoming - the end justifies the means, and so forth.

In C# you simply *cannot* inherit fields along any but the primary
inheritance chain.  Regardless of what you think about the syntax, you
have no implementation choice but to do something along these lines.
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <tS5pc.2989$Yg.1880@fed1read05>
Joe Marshall wrote:

> Ari Johnson <·····@hotmail.com> writes:
> 
> 
>>Joe Marshall wrote:
>>
>>
>>>Ari Johnson <·····@hotmail.com> writes:
>>>
>>>
>>>>A nifty feature of Ruby and C# is property getter/setter methods.
>>>
>>>Um, no.  `Properties' are an artifact of lack of multiple
>>>inheritance.  The kludge of implementing `interfaces' only allows you
>>>to inherit methods, so to fake the inheritance of slots you create
>>>`getter' and `setter' methods so that it almost looks as if you
>>>inherited a field.
>>
>>I disagree.  I may find that the primary shortcoming of both of the
>>languages I cited is lack of multiple inheritance, but their
>>'properties' are more syntactic sugar than a result of that
>>shortcoming - the end justifies the means, and so forth.
> 
> 
> In C# you simply *cannot* inherit fields along any but the primary
> inheritance chain.  Regardless of what you think about the syntax, you
> have no implementation choice but to do something along these lines.

If I thought the language were superior, I wouldn't be asking about 
Lisp.  Like I said, this syntactic sugar in C# is nifty...I don't 
remember claiming that the underlying mechanics were even borderline 
tolerable.

I'm definitely seeing the strengths of CLOS, and I'm sure I'll see more 
as I get further into it.
From: Joe Marshall
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <n04ag4u9.fsf@ccs.neu.edu>
Ari Johnson <·····@hotmail.com> writes:

> Joe Marshall wrote:

>> In C# you simply *cannot* inherit fields along any but the primary
>> inheritance chain.  Regardless of what you think about the syntax, you
>> have no implementation choice but to do something along these lines.
>
> If I thought the language were superior, I wouldn't be asking about
> Lisp.  Like I said, this syntactic sugar in C# is nifty...I don't
> remember claiming that the underlying mechanics were even borderline
> tolerable.

Sorry, that didn't come out how I wanted it to.

The low-level field/property dichotomy is an artifact of a single inheritance.

The high level C# syntax that *hides* this distinction is certainly a
step in the right direction. 

As it happens, however, I'm hacking .NET at a lower level than C# and
*there* you end up writing special cases all over the place for `oh,
that's not a *field*, that's a *property* and although they are
semantically identical, there is an *entirely* different set of
conventions for getting a value'.  (Not to mention the inverse problem
of `oh, that's not *really* a method, it's a property accessor, so you
should pretend it isn't there when someone wants to enumerate the
methods.)

There is this `common wisdom' that multiple inheritance is `bad and
confusing' and that single inheritance and interfaces is all you need.
The problem is that this isn't true.  Yes, perhaps in 99% of the cases
all you need is single inheritance/single dispatch, and perhaps
multiple inheritance should not be used as often as it is, but if you
*remove* the ability altogether you'll end up with very nasty
workarounds when you really need MI.
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <zTdpc.826$wn1.564@fed1read01>
Joe Marshall wrote:

> Ari Johnson <·····@hotmail.com> writes:
> 
> 
>>Joe Marshall wrote:
> 
> 
>>>In C# you simply *cannot* inherit fields along any but the primary
>>>inheritance chain.  Regardless of what you think about the syntax, you
>>>have no implementation choice but to do something along these lines.
>>
>>If I thought the language were superior, I wouldn't be asking about
>>Lisp.  Like I said, this syntactic sugar in C# is nifty...I don't
>>remember claiming that the underlying mechanics were even borderline
>>tolerable.
> 
> 
> Sorry, that didn't come out how I wanted it to.
> 
> The low-level field/property dichotomy is an artifact of a single inheritance.
> 
> The high level C# syntax that *hides* this distinction is certainly a
> step in the right direction. 
> 
> As it happens, however, I'm hacking .NET at a lower level than C# and
> *there* you end up writing special cases all over the place for `oh,
> that's not a *field*, that's a *property* and although they are
> semantically identical, there is an *entirely* different set of
> conventions for getting a value'.  (Not to mention the inverse problem
> of `oh, that's not *really* a method, it's a property accessor, so you
> should pretend it isn't there when someone wants to enumerate the
> methods.)

Like I said, the C# syntax is good, but it's very infrequently indeed 
that nifty syntax relates in any way to nifty implementation.  I didn't 
know that C#/.NET were that bad in this regard, but I don't have a hard 
time believing it.

> There is this `common wisdom' that multiple inheritance is `bad and
> confusing' and that single inheritance and interfaces is all you need.
> The problem is that this isn't true.  Yes, perhaps in 99% of the cases
> all you need is single inheritance/single dispatch, and perhaps
> multiple inheritance should not be used as often as it is, but if you
> *remove* the ability altogether you'll end up with very nasty
> workarounds when you really need MI.

I won't do serious programming in C# or Java as a result of this, and as 
much as I love Ruby as a language I avoid any serious OO programming in 
it, as well.  It seems C++ and Lisp are my only real choices, and I'm 
working on getting into Lisp. :)
From: Mike Kozlowski
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <c84044$pr5$1@reader2.panix.com>
In article <·················@fed1read01>,
Ari Johnson  <·····@hotmail.com> wrote:
>Joe Marshall wrote:

>> As it happens, however, I'm hacking .NET at a lower level than C# and
>> *there* you end up writing special cases all over the place for `oh,
>> that's not a *field*, that's a *property* and although they are
>> semantically identical, there is an *entirely* different set of
>> conventions for getting a value'.  (Not to mention the inverse problem
>> of `oh, that's not *really* a method, it's a property accessor, so you
>> should pretend it isn't there when someone wants to enumerate the
>> methods.)
>
>Like I said, the C# syntax is good, but it's very infrequently indeed 
>that nifty syntax relates in any way to nifty implementation.  I didn't 
>know that C#/.NET were that bad in this regard, but I don't have a hard 
>time believing it.

What you're missing is that MSIL isn't intended to be the
implementation for C# alone -- it's meant to be the implementation for
bunches of languages.  So, properties are compiled down to methods in
the "assembly", and given special attributes so that languages which
support properties know they're special.  It's not an inelegant
solution, given the problem they're solving.

-- 
Mike Kozlowski
http://www.klio.org/mlk/
From: Pascal Costanza
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <c84qh7$6hh$1@newsreader2.netcologne.de>
Mike Kozlowski wrote:

> What you're missing is that MSIL isn't intended to be the
> implementation for C# alone -- it's meant to be the implementation for
> bunches of languages.  So, properties are compiled down to methods in
> the "assembly", and given special attributes so that languages which
> support properties know they're special.  It's not an inelegant
> solution, given the problem they're solving.

I don't think so. C# properties are just a hack to cover the language 
designers' incapability of getting multiple inheritance right. Check out 
user-defined method combinations in CLOS and the protocols for generic 
function invocation and slot access in the CLOS MOP to see how this can 
be solved in a much more general way. I think that Common Lisp is indeed 
much better in terms of conceptual language neutrality.

.NET is just a skinnable Java.


Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <mAqpc.160520$f_5.141167@lakeread01>
Pascal Costanza wrote:

> 
> Mike Kozlowski wrote:
> 
>> What you're missing is that MSIL isn't intended to be the
>> implementation for C# alone -- it's meant to be the implementation for
>> bunches of languages.  So, properties are compiled down to methods in
>> the "assembly", and given special attributes so that languages which
>> support properties know they're special.  It's not an inelegant
>> solution, given the problem they're solving.
> 
> 
> I don't think so. C# properties are just a hack to cover the language 
> designers' incapability of getting multiple inheritance right. Check out 
> user-defined method combinations in CLOS and the protocols for generic 
> function invocation and slot access in the CLOS MOP to see how this can 
> be solved in a much more general way. I think that Common Lisp is indeed 
> much better in terms of conceptual language neutrality.

How do properties cover the lack of MI?  Are properties' getter/setter 
methods inherited from interface classes?  I was turned off enough by C# 
never to bother trying to figure out a good way to do MI (unlike Ruby, 
which has a useful hack to make MI possible).
From: Pascal Costanza
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <c85q3p$8ic$1@newsreader2.netcologne.de>
Ari Johnson wrote:

> Pascal Costanza wrote:
>>
>> Mike Kozlowski wrote:
>>
>>> What you're missing is that MSIL isn't intended to be the
>>> implementation for C# alone -- it's meant to be the implementation for
>>> bunches of languages.  So, properties are compiled down to methods in
>>> the "assembly", and given special attributes so that languages which
>>> support properties know they're special.  It's not an inelegant
>>> solution, given the problem they're solving.
>>
>> I don't think so. C# properties are just a hack to cover the language 
>> designers' incapability of getting multiple inheritance right. Check 
>> out user-defined method combinations in CLOS and the protocols for 
>> generic function invocation and slot access in the CLOS MOP to see how 
>> this can be solved in a much more general way. I think that Common 
>> Lisp is indeed much better in terms of conceptual language neutrality.
> 
> How do properties cover the lack of MI?  Are properties' getter/setter 
> methods inherited from interface classes?  I was turned off enough by C# 
> never to bother trying to figure out a good way to do MI (unlike Ruby, 
> which has a useful hack to make MI possible).

C++/Java/C# have a somewhat "imperative" feel wrt class member 
definitions. Whenever you see a field definition in those languages, it 
actually means "create that field like this, no matter what you have 
seen before". This leads to what they call shadowing (at least in Java) 
- a field with the same name as another field that already exists in a 
superclass is regarded as a different field: All accesses to that name 
via the superclasses go to the original field, and all accesses via the 
current class and subclasses go to the new field.

In Common Lisp, field declarations have a more "declarative" feel. They 
determine a set of properties associated with the field, but they don't 
actually immediately "create" fields. Instead, during the process that 
determines the final structure of a class (class finalization), all the 
field declarations that refer to the same name under which a field 
should be accessible are combined into an effective set of properties, 
and they determine what a field finally looks like.

Java and C# have adopted a somewhat strange mixture of those imperative 
and declarative styles. In interfaces, you can declare methods, but you 
don't actually create them. However, you are not allowed to declare 
fields there, although that would have been perfectly reasonable. A 
field declaration in an interface could just have led to the requirement 
that such a field should exist in any class that declares to implement 
such an interface. This mess was the result of the fact that interfaces 
in Java just evolved from pure abstract classes in the C++ sense. There 
is even an OOPSLA or ECOOP paper published before the advent of Java 
that just describes the idiomatic use of pure abstract classes as 
interfaces in C++, together with the claim that the only reasonable use 
of multiple inheritance is to inherit from one non-abstract and zero or 
more purely abstract superclasses. That's just what the Java designers 
adopted, without thinking deeply enough about the consequences. (And 
this is in fact one of the best indications that C# is just a bad copy 
of Java, because they also just adopted Java's design decisions, with 
only some superficial syntactic sugar added, but without going 
significantly deeper.)

Back to the question what this all has to do with multiple inheritance: 
If interfaces in Java and C# allowed for field declaration, roughly as 
described above, then you would indeed have a first step for a 
reasonable design for proper multiple inheritance. But that would just 
be another instance of Greenspun's tenth rule. Specifically, I disagree 
that C# properties are good solution to a well-understood problem.

The claim that such a bad compromise that evolved from a few false turns 
in accidental language design, is the basis for a so-called 
language-neutral platform is laughable.

Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <2fupc.161610$f_5.65865@lakeread01>
Pascal Costanza wrote:
> 
> Ari Johnson wrote:
> 
>> Pascal Costanza wrote:
>>
>>>
>>> Mike Kozlowski wrote:
>>>
>>>> What you're missing is that MSIL isn't intended to be the
>>>> implementation for C# alone -- it's meant to be the implementation for
>>>> bunches of languages.  So, properties are compiled down to methods in
>>>> the "assembly", and given special attributes so that languages which
>>>> support properties know they're special.  It's not an inelegant
>>>> solution, given the problem they're solving.
>>>
>>>
>>> I don't think so. C# properties are just a hack to cover the language 
>>> designers' incapability of getting multiple inheritance right. Check 
>>> out user-defined method combinations in CLOS and the protocols for 
>>> generic function invocation and slot access in the CLOS MOP to see 
>>> how this can be solved in a much more general way. I think that 
>>> Common Lisp is indeed much better in terms of conceptual language 
>>> neutrality.
>>
>>
>> How do properties cover the lack of MI?  Are properties' getter/setter 
>> methods inherited from interface classes?  I was turned off enough by 
>> C# never to bother trying to figure out a good way to do MI (unlike 
>> Ruby, which has a useful hack to make MI possible).
> 
> 
> C++/Java/C# have a somewhat "imperative" feel wrt class member 
> definitions. Whenever you see a field definition in those languages, it 
> actually means "create that field like this, no matter what you have 
> seen before". This leads to what they call shadowing (at least in Java) 
> - a field with the same name as another field that already exists in a 
> superclass is regarded as a different field: All accesses to that name 
> via the superclasses go to the original field, and all accesses via the 
> current class and subclasses go to the new field.
> 
> In Common Lisp, field declarations have a more "declarative" feel. They 
> determine a set of properties associated with the field, but they don't 
> actually immediately "create" fields. Instead, during the process that 
> determines the final structure of a class (class finalization), all the 
> field declarations that refer to the same name under which a field 
> should be accessible are combined into an effective set of properties, 
> and they determine what a field finally looks like.
> 
> Java and C# have adopted a somewhat strange mixture of those imperative 
> and declarative styles. In interfaces, you can declare methods, but you 
> don't actually create them. However, you are not allowed to declare 
> fields there, although that would have been perfectly reasonable. A 
> field declaration in an interface could just have led to the requirement 
> that such a field should exist in any class that declares to implement 
> such an interface. This mess was the result of the fact that interfaces 
> in Java just evolved from pure abstract classes in the C++ sense. There 
> is even an OOPSLA or ECOOP paper published before the advent of Java 
> that just describes the idiomatic use of pure abstract classes as 
> interfaces in C++, together with the claim that the only reasonable use 
> of multiple inheritance is to inherit from one non-abstract and zero or 
> more purely abstract superclasses. That's just what the Java designers 
> adopted, without thinking deeply enough about the consequences. (And 
> this is in fact one of the best indications that C# is just a bad copy 
> of Java, because they also just adopted Java's design decisions, with 
> only some superficial syntactic sugar added, but without going 
> significantly deeper.)
> 
> Back to the question what this all has to do with multiple inheritance: 
> If interfaces in Java and C# allowed for field declaration, roughly as 
> described above, then you would indeed have a first step for a 
> reasonable design for proper multiple inheritance. But that would just 
> be another instance of Greenspun's tenth rule. Specifically, I disagree 
> that C# properties are good solution to a well-understood problem.
> 
> The claim that such a bad compromise that evolved from a few false turns 
> in accidental language design, is the basis for a so-called 
> language-neutral platform is laughable.

You haven't addressed my question.  Upon experimentation, C# 'interface' 
classes can't have getter/setter methods defined, getting the exact same 
error (CS0531 'interface members cannot have a definition') as if you 
try to give an interface a member function definition.

How exactly, then, do C#'s properties cover up for lack of MI?
From: Pedro Pinto
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <Skupc.24335$zq4.1524896@twister.southeast.rr.com>
Ari Johnson wrote:
> You haven't addressed my question.  Upon experimentation, C# 'interface' 
> classes can't have getter/setter methods defined, getting the exact same 
> error (CS0531 'interface members cannot have a definition') as if you 
> try to give an interface a member function definition.


Perhaps you did not use the right sintax?

		interface X
		{
			bool x
			{get;}
		}

is legal C#.

-pp
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <ppupc.161643$f_5.133798@lakeread01>
Pedro Pinto wrote:

> Ari Johnson wrote:
> 
>> You haven't addressed my question.  Upon experimentation, C# 
>> 'interface' classes can't have getter/setter methods defined, getting 
>> the exact same error (CS0531 'interface members cannot have a 
>> definition') as if you try to give an interface a member function 
>> definition.
> 
> 
> 
> Perhaps you did not use the right sintax?
> 
>         interface X
>         {
>             bool x
>             {get;}
>         }
> 
> is legal C#.

That's a declaration, not a definition.  Try
   interface X { bool x { get { return false } } }

This makes sense, of course, but the original point I'm disputing is 
that properties do anything to cover up for lack of MI.
From: Pascal Costanza
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <c868q4$6gm$1@newsreader2.netcologne.de>
Ari Johnson wrote:

> Pedro Pinto wrote:
> 
>> Ari Johnson wrote:
>>
>>> You haven't addressed my question.  Upon experimentation, C# 
>>> 'interface' classes can't have getter/setter methods defined, getting 
>>> the exact same error (CS0531 'interface members cannot have a 
>>> definition') as if you try to give an interface a member function 
>>> definition.
>>
>> Perhaps you did not use the right sintax?
>>
>>         interface X
>>         {
>>             bool x
>>             {get;}
>>         }
>>
>> is legal C#.
> 
> That's a declaration, not a definition.  Try
>   interface X { bool x { get { return false } } }

...this is important here: Java and C# allow for multiple inheritance of 
declarations, but not of definitions.

> This makes sense, of course, but the original point I'm disputing is 
> that properties do anything to cover up for lack of MI.

The trick in Common Lisp is that you can "only" _declare_ slots (fields) 
in DEFCLASS forms. The actual slot _definition_ (in the Java/C# sense) 
is combined from the various declarations that are mentioned in the 
class and its superclasses.

You can't have multiple inheritance for fields in Java and C#, therefore 
you have to resort to setter/getter methods aka properties in order to 
simulate multiple inheritance of fields.

(There is another "reason" for setter/getter methods in Java/C# - they 
allow you to override the setting/getting behavior in subclasses. But 
there's no fundamental reason that this shouldn't be possible for fields 
also. In fact, that is what SLOT-VALUE-USING-CLASS in the CLOS 
Metaobject Protocol allows you to do. AspectJ also provides a workaround.)


Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <CRxpc.62721$Fl5.61684@okepread04>
Pascal Costanza wrote:

> 
> Ari Johnson wrote:
> 
>> Pedro Pinto wrote:
>>
>>> Ari Johnson wrote:
>>>
>>>> You haven't addressed my question.  Upon experimentation, C# 
>>>> 'interface' classes can't have getter/setter methods defined, 
>>>> getting the exact same error (CS0531 'interface members cannot have 
>>>> a definition') as if you try to give an interface a member function 
>>>> definition.
>>>
>>>
>>> Perhaps you did not use the right sintax?
>>>
>>>         interface X
>>>         {
>>>             bool x
>>>             {get;}
>>>         }
>>>
>>> is legal C#.
>>
>>
>> That's a declaration, not a definition.  Try
>>   interface X { bool x { get { return false } } }
> 
> 
> ...this is important here: Java and C# allow for multiple inheritance of 
> declarations, but not of definitions.

That's kind of my point - MI is no good if you only inherit the 
interface, which is the case here.  I want to inherit the actual 
properties and methods of the parent class, not just the way it looks to 
the outside world and then have to reimplement it all on my own.  This 
only serves to create bugs by people incorrectly implementing interfaces 
in subclasses.  It's like a woman giving birth to mannequins - they may 
look like people on the outside, but all of the internal functionality 
is missing.

Ruby gets around this by mixins.  You can do

Module cool_features
   # Cool methods, properties, members, and whatnot can go here
end

Class Bob
   include cool_features # now Bob has those methods, et al.
end

At least their pseudo-inheritance allows this, although it still falls 
short in that Bob is not actually in the class hierarchy of cool_features.

>> This makes sense, of course, but the original point I'm disputing is 
>> that properties do anything to cover up for lack of MI.
> 
> 
> The trick in Common Lisp is that you can "only" _declare_ slots (fields) 
> in DEFCLASS forms. The actual slot _definition_ (in the Java/C# sense) 
> is combined from the various declarations that are mentioned in the 
> class and its superclasses.

You're just being pedantic.  If I define a slot with an accessor method 
and then create a subclass, I inherit the functionality provided by the 
accessor method.  I don't have to redefine and reimplement everything in 
every subclass.

> You can't have multiple inheritance for fields in Java and C#, therefore 
> you have to resort to setter/getter methods aka properties in order to 
> simulate multiple inheritance of fields.

Again, you're prone to erroneously implement those methods.  The only 
value I see in C#'s properties (albeit a great value for writing 
readable code) is the syntactic element.  I can do things like
   myarray a;
   ...
   a.length = 5;
and not worry about whether myarray::length is a public data member or a 
public property.

> (There is another "reason" for setter/getter methods in Java/C# - they 
> allow you to override the setting/getting behavior in subclasses. But 
> there's no fundamental reason that this shouldn't be possible for fields 
> also. In fact, that is what SLOT-VALUE-USING-CLASS in the CLOS 
> Metaobject Protocol allows you to do. AspectJ also provides a workaround.)

I don't know much at all about MOP at this point, so I can't comment.
From: Pascal Costanza
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <c86atd$aib$1@newsreader2.netcologne.de>
Ari Johnson wrote:

> Pascal Costanza wrote:
[...]

>> The trick in Common Lisp is that you can "only" _declare_ slots 
>> (fields) in DEFCLASS forms. The actual slot _definition_ (in the 
>> Java/C# sense) is combined from the various declarations that are 
>> mentioned in the class and its superclasses.
> 
> You're just being pedantic.  If I define a slot with an accessor method 
> and then create a subclass, I inherit the functionality provided by the 
> accessor method.  I don't have to redefine and reimplement everything in 
> every subclass.

It's more than that. You can also define new accessors in the subclass, 
and then you can use all the accessors from the superclasses and the 
newly created ones. The type of a slot is the intersection of all the 
type declarations from the superclasses and the current class. And so 
on. See section 7.5.3 in the HyperSpec. You can add your own slot 
options and your own combination rules via the MOP.

Yes, it's a pedantic view, but that's how it is.

>> You can't have multiple inheritance for fields in Java and C#, 
>> therefore you have to resort to setter/getter methods aka properties 
>> in order to simulate multiple inheritance of fields.
> 
> Again, you're prone to erroneously implement those methods.

I didn't say that the Java/C# doesn't suck. ;)

> The only 
> value I see in C#'s properties (albeit a great value for writing 
> readable code) is the syntactic element.  I can do things like
>   myarray a;
>   ...
>   a.length = 5;
> and not worry about whether myarray::length is a public data member or a 
> public property.

Right. But proper multiple inheritance for fields, with some reasonable 
and configurable rules for resolving conflicts, would have been better, 
at least at the MSIL level.


Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <jRypc.62934$Fl5.15694@okepread04>
Pascal Costanza wrote:

> 
> 
> Ari Johnson wrote:
> 
>> Pascal Costanza wrote:
> 
> [...]
> 
>>> The trick in Common Lisp is that you can "only" _declare_ slots 
>>> (fields) in DEFCLASS forms. The actual slot _definition_ (in the 
>>> Java/C# sense) is combined from the various declarations that are 
>>> mentioned in the class and its superclasses.
>>
>>
>> You're just being pedantic.  If I define a slot with an accessor 
>> method and then create a subclass, I inherit the functionality 
>> provided by the accessor method.  I don't have to redefine and 
>> reimplement everything in every subclass.
> 
> 
> It's more than that. You can also define new accessors in the subclass, 
> and then you can use all the accessors from the superclasses and the 
> newly created ones. The type of a slot is the intersection of all the 
> type declarations from the superclasses and the current class. And so 
> on. See section 7.5.3 in the HyperSpec. You can add your own slot 
> options and your own combination rules via the MOP.
> 
> Yes, it's a pedantic view, but that's how it is.

Well, I wasn't wrong in giving a subset of the features available. :)

>>> You can't have multiple inheritance for fields in Java and C#, 
>>> therefore you have to resort to setter/getter methods aka properties 
>>> in order to simulate multiple inheritance of fields.
>>
>>
>> Again, you're prone to erroneously implement those methods.
> 
> 
> I didn't say that the Java/C# doesn't suck. ;)
> 
>> The only value I see in C#'s properties (albeit a great value for 
>> writing readable code) is the syntactic element.  I can do things like
>>   myarray a;
>>   ...
>>   a.length = 5;
>> and not worry about whether myarray::length is a public data member or 
>> a public property.
> 
> 
> Right. But proper multiple inheritance for fields, with some reasonable 
> and configurable rules for resolving conflicts, would have been better, 
> at least at the MSIL level.

"Better", yes, but the best would be to have both the nifty syntax and 
proper multiple inheritance. :)

Anyone who claims there is no use for multiple inheritance is a bastard 
and wants everyone else to be one, too.
From: Antonio Menezes Leitao
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <pan.2004.05.16.14.02.19.376153@evaluator.pt>
On Sat, 15 May 2004 16:38:13 -0700, Ari Johnson wrote:

> [...]
> Ruby gets around this by mixins.  You can do
> 
> Module cool_features
>    # Cool methods, properties, members, and whatnot can go here
> end
> 
> Class Bob
>    include cool_features # now Bob has those methods, et al.
> end
> 
> At least their pseudo-inheritance allows this, although it still falls 
> short in that Bob is not actually in the class hierarchy of cool_features.

Linj also uses mixins but the including class does belong to both
hierarchies.  Here's one example:

;;A mixin with one slot and two methods (a reader and a writter)
(defmixin cool-features ()
  ((cool-slot :initform 123 :initarg :cool-slot :accessor cool-slot)))

;;A class that includes the mixin (and inherits from object)
(defclass bob (cool-features object)
  ())

After translation to Java, you get:

interface CoolFeatures {

    public abstract int coolSlot();

    public abstract int setfCoolSlot(int coolSlot);
}

class Bob extends Object implements CoolFeatures {

    public Bob(int coolSlot) {
        this.coolSlot = coolSlot;
    }

    public int setfCoolSlot(int coolSlot) {
        return this.coolSlot = coolSlot;
    }

    public int coolSlot() {
        return coolSlot;
    }

    protected int coolSlot = 123;
}

As you can see, class Bob inherits from Object but also
belongs to type CoolFeatures.  It also includes the slot definition that
was present in cool-features and implements the abstract methods described
in CoolFeatures.  The good thing is that this was all done automatically
by the Linj compiler.

Antonio Leitao.
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <2nNpc.64916$Fl5.30033@okepread04>
Antonio Menezes Leitao wrote:

> On Sat, 15 May 2004 16:38:13 -0700, Ari Johnson wrote:
> 
> 
>>[...]
>>Ruby gets around this by mixins.  You can do
>>
>>Module cool_features
>>   # Cool methods, properties, members, and whatnot can go here
>>end
>>
>>Class Bob
>>   include cool_features # now Bob has those methods, et al.
>>end
>>
>>At least their pseudo-inheritance allows this, although it still falls 
>>short in that Bob is not actually in the class hierarchy of cool_features.
> 
> 
> Linj also uses mixins but the including class does belong to both
> hierarchies.  Here's one example:
> 
> ;;A mixin with one slot and two methods (a reader and a writter)
> (defmixin cool-features ()
>   ((cool-slot :initform 123 :initarg :cool-slot :accessor cool-slot)))
> 
> ;;A class that includes the mixin (and inherits from object)
> (defclass bob (cool-features object)
>   ())
> 
> After translation to Java, you get:
> 
> interface CoolFeatures {
> 
>     public abstract int coolSlot();
> 
>     public abstract int setfCoolSlot(int coolSlot);
> }
> 
> class Bob extends Object implements CoolFeatures {
> 
>     public Bob(int coolSlot) {
>         this.coolSlot = coolSlot;
>     }
> 
>     public int setfCoolSlot(int coolSlot) {
>         return this.coolSlot = coolSlot;
>     }
> 
>     public int coolSlot() {
>         return coolSlot;
>     }
> 
>     protected int coolSlot = 123;
> }
> 
> As you can see, class Bob inherits from Object but also
> belongs to type CoolFeatures.  It also includes the slot definition that
> was present in cool-features and implements the abstract methods described
> in CoolFeatures.  The good thing is that this was all done automatically
> by the Linj compiler.

That's the only good thing, though.  Doing MI by hand in Java is much 
more painful than that.
From: Ari Johnson
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <Lj5qc.68157$Fl5.25894@okepread04>
Joe Marshall wrote:
> Ari Johnson <·····@hotmail.com> writes:
> 
> 
>>How exactly, then, do C#'s properties cover up for lack of MI?
<snip>
> The C# `property' syntax mimics this by automagically translating
> my_pet.property to my_pet.GetProperty() where necessary so that the
> user doesn't need to remember the irrelevant distinction.

Fair enough, but you still have to reimplement the setter and getter 
methods in every subclass, so it covers up for lack of MI for the user's 
point of view, but does nothing for the implementor.  I don't like 
half-assed solutions.
From: Antonio Menezes Leitao
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <pan.2004.05.15.23.31.51.759906@evaluator.pt>
On Sat, 15 May 2004 21:12:57 +0200, Pascal Costanza wrote:

> [...]
> Java and C# have adopted a somewhat strange mixture of those imperative 
> and declarative styles. In interfaces, you can declare methods, but you 
> don't actually create them. However, you are not allowed to declare 
> fields there, although that would have been perfectly reasonable. A 
> field declaration in an interface could just have led to the requirement 
> that such a field should exist in any class that declares to implement 
> such an interface. This mess was the result of the fact that interfaces 
> in Java just evolved from pure abstract classes in the C++ sense. There 
> is even an OOPSLA or ECOOP paper published before the advent of Java 
> that just describes the idiomatic use of pure abstract classes as 
> interfaces in C++, together with the claim that the only reasonable use 
> of multiple inheritance is to inherit from one non-abstract and zero or 
> more purely abstract superclasses. That's just what the Java designers 
> adopted, without thinking deeply enough about the consequences. (And 
> this is in fact one of the best indications that C# is just a bad copy 
> of Java, because they also just adopted Java's design decisions, with 
> only some superficial syntactic sugar added, but without going 
> significantly deeper.)
> 
> Back to the question what this all has to do with multiple inheritance: 
> If interfaces in Java and C# allowed for field declaration, roughly as 
> described above, then you would indeed have a first step for a 
> reasonable design for proper multiple inheritance. But that would just 
> be another instance of Greenspun's tenth rule. Specifically, I disagree 
> that C# properties are good solution to a well-understood problem.

I suggest you take a look at Linj, the Lisp to Java translator.  Linj
implements a poor's man approach to multiple inheritance based on the idea
of mixins: you inherit from one base class and any number of mixins.
Mixins are classes that inherit from other mixins and that can't be
instantiated but, other than that, they don't have limitations: you can
define slots and/or methods just like in normal classes.  When these
mixins are translated into Java interfaces they loose the non-constant
slots and the methods become abstract (loosing their bodies).  However,
classes that inherit from the mixin will get copies of the remaining slots
slots and of the methods.

It can lead to code bloat, of course, but it's much better than doing code
bloat by hand, humm, I mean, copy & paste  :-)

Antonio Leitao.
From: Pascal Costanza
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <c883jm$s40$1@newsreader2.netcologne.de>
Antonio Menezes Leitao wrote:

> I suggest you take a look at Linj, the Lisp to Java translator.

I haven't checked it yet, but I have looked at the documentation when 
you first mentioned it here in c.l.l. Indeed, I think this is a very 
cool idea. If I ever happen to need to use Java again, LinJ is one of 
the first tools I will look into.

A minor suggestion for improvement: The download site doesn't mention 
the platforms on which LinJ runs. It seems to me that the downloads 
contain precompiled fasl files, and they probably don't run on, say, Mac 
OS X, right?

Just add a few lines to make this clear...


Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: Mike Kozlowski
Subject: Re: CLOS Properties Question
Date: 
Message-ID: <c854cq$5c8$1@reader2.panix.com>
In article <············@newsreader2.netcologne.de>,
Pascal Costanza  <········@web.de> wrote:
>Mike Kozlowski wrote:
>
>> What you're missing is that MSIL isn't intended to be the
>> implementation for C# alone -- it's meant to be the implementation for
>> bunches of languages.  So, properties are compiled down to methods in
>> the "assembly", and given special attributes so that languages which
>> support properties know they're special.  It's not an inelegant
>> solution, given the problem they're solving.
>
>I don't think so. C# properties are just a hack to cover the language 
>designers' incapability of getting multiple inheritance right.

You're talking about a completely different point than I am.  I'm
explaining why properties compile down to regular methods with a
special flag in MSIL (to follow the CLS rules of allowing
least-common-denominator languages to access libraries from other
languages), not why C# has properties at all.

-- 
Mike Kozlowski
http://www.klio.org/mlk/