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

Namespaces, packages, and methods

10 views
Skip to first unread message

Johann Hibschman

unread,
May 13, 2001, 8:15:54 PM5/13/01
to
Hi folks,

I've been trying to learn CLOS, and I've become confused by some
naming issues.

In a few classes, I've found that I wanted to define a method with
the same name as a CL built-in function, such as "find", "position",
and "reverse".

I cannot simply define such a method, since it conflicts with the
normal definition of the function. I can't define it in a package,
since I would then have to not include the common lisp package and
preface all of my CL symbols with "cl::".

Even if I could define such a thing within a package, I could not
include two packages, each of which defines a method, into the same
program without conflicts.

Is there anything I can do, or is this just something I have to learn
not to do? This just grates on me somehow, since I come from languages
where a class is its own namespace and such issues never arise, but
perhaps I'm misunderstanding things.

What happens if I have foo::method and bar::method and then try to
load both foo and bar into one file?

I'm afraid I'm rambling a bit, but the interaction between the idea of
generic functions, which add specializations to a global object, and
packages confuses me. If you could lend any insight, I'd appreciate
it.

Thanks,

--Johann

Kent M Pitman

unread,
May 13, 2001, 8:34:07 PM5/13/01
to
Johann Hibschman <joh...@uclink.berkeley.edu> writes:

> I've been trying to learn CLOS, and I've become confused by some
> naming issues.
>
> In a few classes, I've found that I wanted to define a method with
> the same name as a CL built-in function, such as "find", "position",
> and "reverse".
>
> I cannot simply define such a method, since it conflicts with the
> normal definition of the function. I can't define it in a package,
> since I would then have to not include the common lisp package and
> preface all of my CL symbols with "cl::".

No, you can do it.

Check out the ability to shadow and shadowing-import.

In this case, just

(defpackage "MY-PACKAGE"
(:use "CL")
(:shadow "FIND" "POSITION" "REVERSE"))

will leave you ok.

> Even if I could define such a thing within a package, I could not
> include two packages, each of which defines a method, into the same
> program without conflicts.

This is what :shadowing-import-from is for.

(defpackage "MY-PACKAGE-2"
(:use "CL" "MY-PACKAGE")
(:shadowing-import-from "MY-PACKAGE"
"FIND" "POSITION")
(:shadowing-import-from "CL"
"REVERSE"))

> Is there anything I can do, or is this just something I have to learn
> not to do? This just grates on me somehow, since I come from languages
> where a class is its own namespace and such issues never arise, but
> perhaps I'm misunderstanding things.

Most languages have to confront the issue of inheriting names, and, when
such inheritance comes into conflict, resolving the conflict. CL's tools
for this are not perfect, but they can be made to work.



> What happens if I have foo::method and bar::method and then try to
> load both foo and bar into one file?

I'm not sure I understand your question. Is method an actual symbol
here or a metasyntactic variable meaning "some arbitrarily selected
method name"? What does it mean to load foo and bar into a file?
Files are not something you load into--they are something you load
from. If you clarify your question, it can probably be answered. I'm
too lazy to answer all the possible questions you might have asked.

> I'm afraid I'm rambling a bit, but the interaction between the idea of
> generic functions, which add specializations to a global object, and
> packages confuses me. If you could lend any insight, I'd appreciate
> it.

Generic functions add specializations to types, not names.

Types have meaning only in how they relate to other types by type inheritance.

Symbols are a way of naming classes. Different symbols name different classes.

Symbols also name generic functions. Different symbols name different gf's.

Objects are not specialized, classes are.

I'm not trying to be obtuse but I'm just not sure what your question is.
Perhaps you could rephrase it or offer a worked example.

Erik Naggum

unread,
May 14, 2001, 8:23:52 AM5/14/01
to
* Johann Hibschman <joh...@uclink.berkeley.edu>
> ... since I come from languages where a class is its own namespace and
> such issues never arise ...

What you are really saying here is that you have been able to internalize
the rules of that language such that you do not cause the issues to arise.
Thsoe who have internalized the rules of Common Lisp do not want to call
their functions "find" or "position" or "reverse". It is that simple.

Different language, different issues. If you are unwilling to learn to
work _in_ the language you are now using/learning, but somehow think that
you should apply the rules and internalizations of another language to
it, you will in fact never become comfortable with _any_ other language
than your first. I _suspect_ that the way you learned your first
language was not a process of understanding, but a process of copying.
This is quite common, but as people go on to learn more languages, they
find that memory and patterns of doing things work well for one language
(or context) at a time. It is also faster to do things by memorized
patterns than to think, so the process of learning a new language has
some serious drawbacks. Some languages are even so hard to learn that
they force people to use but a subset of their patterns of doing things.
Both Perl and C++ come to mind. Learning by doing is sometimes touted as
a good way to learn, but I think it is a good way to learn only one thing
of a kind. To learn something different, you first have to study what
you already know to understand why, not just know how.

#:Erik
--
Travel is a meat thing.

Johann Hibschman

unread,
May 14, 2001, 1:43:50 PM5/14/01
to
In article <sfwy9s0...@world.std.com>, Kent M Pitman
<pit...@world.std.com> wrote:

> No, you can do it.
>
> Check out the ability to shadow and shadowing-import.

Ah, thank you, that helps.

> > What happens if I have foo::method and bar::method and then try to
> > load both foo and bar into one file?
>
> I'm not sure I understand your question. Is method an actual symbol
> here or a metasyntactic variable meaning "some arbitrarily selected
> method name"? What does it mean to load foo and bar into a file?
> Files are not something you load into--they are something you load
> from. If you clarify your question, it can probably be answered. I'm
> too lazy to answer all the possible questions you might have asked.

That was rather astoundingly unclear, I admit.

What I meant to ask was, if I have two packages each of which defines a
generic function on a symbol interned in that package, such as

---
(defpackage "PEOPLE" ...)
(in-package "PEOPLE")
(defclass person ...)
(defmethod eat ((p person) food) ...)
---
and
---
(defpackage "ANIMALS" ...)
(in-package "ANIMALS")
(defclass cat ...)
(defmethod eat ((c cat) food) ...)
---

is there a way that I could merge the definitions of these two functions
so that elsewhere I could write

(eat thing food)

and have it dispatch correctly on either a person or a cat?

As I understand it, the above code definies a people:eat symbol and a
animals:eat symbol, each of which names a separate generic function,
which would make what I ask impossible. Is this correct?

Also, would I stylistically be better off naming these functions
animal-eat and person-eat, i.e. with a class prefix, so as to avoid
possible name clashes?

Thanks,

--Johann

Johann Hibschman

unread,
May 14, 2001, 1:56:46 PM5/14/01
to
In article <31988318...@naggum.net>, Erik Naggum <er...@naggum.net>
wrote:

> * Johann Hibschman <joh...@uclink.berkeley.edu>
> > ... since I come from languages where a class is its own namespace and
> > such issues never arise ...
>
> What you are really saying here is that you have been able to internalize
> the rules of that language such that you do not cause the issues to arise.
> Thsoe who have internalized the rules of Common Lisp do not want to call
> their functions "find" or "position" or "reverse". It is that simple.

If I create a class, implementing an array-like collection, perhaps a
ring-like buffer, what would you recommend I name the function to
return the index of a given item? Would "ring-position" be better
style?

That approach seems to suggest that all methods names be prefixed by the
name of their primary or base class, which seems (at first glance)
awkward, overly verbose, and redundant, since the type information is
already stored in the dispatch table of the generic function.

Thanks,

--Johann

Sashank Varma

unread,
May 14, 2001, 2:55:05 PM5/14/01
to
In article <130520011715543536%joh...@uclink.berkeley.edu>, Johann
Hibschman <joh...@uclink.berkeley.edu> wrote:
[snip]

>In a few classes, I've found that I wanted to define a method with
>the same name as a CL built-in function, such as "find", "position",
>and "reverse".
>
>I cannot simply define such a method, since it conflicts with the
>normal definition of the function.
[snip]

I think your original confusion is because some of the built-in functions
of CL are just that, functions, while others are *generic* functions. FIND,
POSITION, and REVERSE are in the former, function category. You can't
"overload" them anymore than you can overload SCANF in C.

You *can* overload generic functions in the sense that you can define
new methods for them...

In article <140520011043503603%joh...@uclink.berkeley.edu>, Johann
Hibschman <joh...@uclink.berkeley.edu> wrote:
[snip]


>What I meant to ask was, if I have two packages each of which defines a
>generic function on a symbol interned in that package, such as
>
>---
>(defpackage "PEOPLE" ...)
>(in-package "PEOPLE")
>(defclass person ...)
>(defmethod eat ((p person) food) ...)
>---
> and
>---
>(defpackage "ANIMALS" ...)
>(in-package "ANIMALS")
>(defclass cat ...)
>(defmethod eat ((c cat) food) ...)
>---
>
>is there a way that I could merge the definitions of these two functions
>so that elsewhere I could write
>
> (eat thing food)
>
>and have it dispatch correctly on either a person or a cat?

This code will work as is, with no need for package manipulations to
establish namespaces:

? (defclass person () ())
#<STANDARD-CLASS PERSON>
? (defmethod eat ((p person) food)
(format t "~%~A is yummy! " food))
#<STANDARD-METHOD EAT (PERSON T)>
? (defclass cat () ())
#<STANDARD-CLASS CAT>
? (defmethod eat ((c cat) food)
(format t "~%~A meow meow! " food))
#<STANDARD-METHOD EAT (CAT T)>
? (eat (make-instance 'person) "Spam")

Spam is yummy!
NIL
? (eat (make-instance 'cat) "Spam")

Spam meow meow!
NIL
?

CL classes don't contain their methods; generic functions do. Generic
functions dispatch on the types of their arguments, selecting the
appropriate method(s) to run. BUT, none of this applies to conventional
functions, such as FIND, POSITION, and REVERSE -- the one's that gave
you your initial trouble. They can't be overloaded, and must be
shadowed as others have shown.

Sashank

Marco Antoniotti

unread,
May 14, 2001, 3:08:27 PM5/14/01
to

Johann Hibschman <joh...@uclink.berkeley.edu> writes:

(defpackage "FOOD" ...)
(in-package "FOOD")

(defmethod eat ((c animals:cat) food) ; Assuming "CAT" and "EAT" are exported.
(animals:eat c food))

(defmethod eat ((c people:person) food)
(people:eat c food))

I don't see the problem.

> As I understand it, the above code definies a people:eat symbol and a
> animals:eat symbol, each of which names a separate generic function,
> which would make what I ask impossible. Is this correct?

Yes it is.

> Also, would I stylistically be better off naming these functions
> animal-eat and person-eat, i.e. with a class prefix, so as to avoid
> possible name clashes?

I believe you'd better think about your model. Why should EAT be
something peculiar to the ANIMAL package or the PEOPLE package?

EAT is an action performed by both, therefore, thinking about your
model in a different way may make your life easier.

All in all your way of packaging things is obviously a translation of
C++/Java/new-language-on-the-block-avec-forced-indentation-rules.
You can, but in CL it is better to thinks about other ways of doing
things.

Cheers

--
Marco Antoniotti ========================================================
NYU Courant Bioinformatics Group tel. +1 - 212 - 998 3488
719 Broadway 12th Floor fax +1 - 212 - 995 4122
New York, NY 10003, USA http://bioinformatics.cat.nyu.edu
"Hello New York! We'll do what we can!"
Bill Murray in `Ghostbusters'.

Jon S Anthony

unread,
May 14, 2001, 8:14:06 PM5/14/01
to
Johann Hibschman wrote:

> What I meant to ask was, if I have two packages each of which
> defines a generic function on a symbol interned in that package,
> such as
>
> ---
> (defpackage "PEOPLE" ...)
> (in-package "PEOPLE")
> (defclass person ...)
> (defmethod eat ((p person) food) ...)
> ---
> and
> ---
> (defpackage "ANIMALS" ...)
> (in-package "ANIMALS")
> (defclass cat ...)
> (defmethod eat ((c cat) food) ...)
> ---

Just to be clear, with just the information you've written there may
be one or two generic functions with two or one "implementations" -
methods. In the absence of an explicit defgeneric a defmethod will
declare one, so depending on whether your packages import/use symbols
from another package(s) where a suitable generic is declared you may
have several situations here.

> is there a way that I could merge the definitions of these two
> functions so that elsewhere I could write
>
> (eat thing food)
>
> and have it dispatch correctly on either a person or a cat?

Without making use of shadowing (as Kent mentioned) you can also do
something "brute force" like the following (which uses full package
using...)


(defpackage base
(:use "COMMON-LISP"))
(in-package :base)

;;; This is the prototypical signature for all eating...
;;;
(defgeneric eat ((x t) food))

;;; This is what gets dispatched if you screw up...
(defmethod eat ((x t) food)
(format t "~%~A does not know how to eat ~A" x food))

(export 'eat)


(defpackage "PEOPLE"
(:use "COMMON-LISP" "BASE"))
(in-package :people)

(defclass person () ())

(defmethod eat ((p person) food)

(format t "~%Person eats ~A" food))

(export '(person eat))

(defpackage "ANIMALS"
(:use "COMMON-LISP" "BASE"))
(in-package :animals)

(defclass cat () ())

(defmethod eat ((c cat) food)

(format t "~%Cat eats ~A" food))

(export '(cat eat))

(defpackage "WHATEVER"
(:use "COMMON-LISP" "ANIMALS" "PEOPLE"))

(in-package :whatever)

(let ((felix (make-instance 'cat))
(marie (make-instance 'person)))
(eat marie :cake)
(eat felix :trash)
(eat 23 :prime))

==>
Person eats CAKE
Cat eats TRASH
23 does not know how to eat PRIME


/Jon

--
Jon Anthony
Synquiry Technologies, Ltd. Belmont, MA 02478, 617.484.3383
"Nightmares - Ha! The way my life's been going lately,
Who'd notice?" -- Londo Mollari

Kent M Pitman

unread,
May 15, 2001, 3:50:21 AM5/15/01
to
Johann Hibschman <joh...@uclink.berkeley.edu> writes:

> What I meant to ask was, if I have two packages each of which defines a
> generic function on a symbol interned in that package, such as
>
> ---
> (defpackage "PEOPLE" ...)
> (in-package "PEOPLE")
> (defclass person ...)
> (defmethod eat ((p person) food) ...)
> ---
> and
> ---
> (defpackage "ANIMALS" ...)
> (in-package "ANIMALS")
> (defclass cat ...)
> (defmethod eat ((c cat) food) ...)
> ---
>
> is there a way that I could merge the definitions of these two functions
> so that elsewhere I could write
>
> (eat thing food)
>
> and have it dispatch correctly on either a person or a cat?
>

> As I understand it, the above code defines a people:eat symbol and a


> animals:eat symbol, each of which names a separate generic function,
> which would make what I ask impossible. Is this correct?

Yes.

As others have indicated, you can certainly make one or the other annex
the other. e.g.,

(defmethod people:eat ((c animals:cat) food)
(animals:eat c food))

However, you always get a master/slave relation when you do this. When
you define methods on ANIMALS:EAT, you implicitly get them in the PEOPLE:EAT
because you're cross-calling, but methods on PEOPLE:EAT don't get seen by
ANIMALS:EAT.

You're better off to share the symbol EAT as in

(defpackage "COMMON-ACTIONS"
(:use)
(:export "EAT" "FOOD"))

(defpackage "PEOPLE"
(:use "CL" "COMMON-ACTIONS"))

(defpackage "ANIMALS"
(:use "CL" "COMMON-ACTIONS"))

In this way, the symbols PEOPLE::EAT and PEOPLE::FOOD are EQ to
COMMON-ACTIONS:EAT and COMMON-ACTIONS:FOOD.

> Also, would I stylistically be better off naming these functions
> animal-eat and person-eat, i.e. with a class prefix, so as to avoid
> possible name clashes?

No. That's generally the wrong thing.

The main reason why you might want to make an ANIMAL-EAT and a PERSON-EAT
are:

* You plan to import your package into someplace that has an EAT
verb already which is incompatibly defined and/or not a gf.

* These verbs really take different args for legitimate reasons
that make it bad to consolidate them. Your verb EAT probably won't
have this problem, but let's say you used the word BOX. It might
mean "to encase in a cardboard container" or "to fist-fight with gloves".
In this case, a prefix argument is better than trying to shoehorn
both meanings into the same verb.

Ordinarily, though, I'd just stick with the simple name.

Over time, I've been gradually fixing all the FOO-NAME and BAR-NAME
operators in my code to just be NAME, for example...

Kent M Pitman

unread,
May 15, 2001, 4:04:47 AM5/15/01
to
Johann Hibschman <joh...@uclink.berkeley.edu> writes:

>
> In article <31988318...@naggum.net>, Erik Naggum <er...@naggum.net>
> wrote:
>
> > * Johann Hibschman <joh...@uclink.berkeley.edu>
> > > ... since I come from languages where a class is its own namespace and
> > > such issues never arise ...
> >
> > What you are really saying here is that you have been able to internalize
> > the rules of that language such that you do not cause the issues to arise.
> > Thsoe who have internalized the rules of Common Lisp do not want to call
> > their functions "find" or "position" or "reverse". It is that simple.
>
> If I create a class, implementing an array-like collection, perhaps a
> ring-like buffer, what would you recommend I name the function to
> return the index of a given item? Would "ring-position" be better
> style?

Many consider it an annoyance that FIND and friends are not generic.
There were some good reasons for not making them be, but there are
arguments on the other side as well. It's a lamentable situation
either way.

I'd probably not think RING-POSITION was a terrible name, though another
way to go is to do the shadow thing we discussed before, and yet another
solution is to pick another neutral name.

(defmethod index-of (purported-element (sequence sequence))
(position purported-element sequence))

(defmethod index-of (purported-element (ring-buffer ring-buffer))
... carefully look for position ...)

Or even POSITION-OF.

Likewise you might decide to rename REVERSE to REVERSE-OF or
BACkWARDS or MIRROR or REVERSE-ORDER. And you might call FIND
SEEK, VERIFY-PRESENCE, etc.

Choosing a naming convention that is memorable is handy, though.
It's tough because FIND is a verb while POSITION is a noun and
REVERSE is either a verb or an adjective. But, for example, if you
called it *FIND, *POSITION, and *REVERSE, at least it would be easy
for people to guess the name once they understood your problem.
Then again, choosing to just shadow things works the same effect.

> That approach seems to suggest that all methods names be prefixed by the
> name of their primary or base class, which seems (at first glance)
> awkward, overly verbose, and redundant, since the type information is
> already stored in the dispatch table of the generic function.

Right. Well, as I mentioned in another note, that's mostly only useful
if you want to be an "inconspicuous" class. Often, picking a short generic
name will collide with someone else's chosen names in another system, and
that can be hell when you go to try to sort out the symbol conflicts.
It may result in people using your package less for fear of conflicts.
So in practice, picking names that are obscure lessens the risk of problem.
But other than that little social problem, I do think picking the short names
is better--when you're really making something generic...

A word on that--

I use the word generic to mean "having the same abstract contract".
Java, for example, has "foo"+"bar" => "foobar". I don't consider
that generic. That's what I call overloading. Overloading is when
you, in a semantics-free way, just pour two things into the same name.

Johann Hibschman

unread,
May 15, 2001, 12:34:37 PM5/15/01
to
In article <sfwr8xr...@world.std.com>, Kent M Pitman
<pit...@world.std.com> wrote:

First off, thanks for replying, and thanks to everyone else who's
posted. I'm slowly integrating a picture of how this system works.
The simple language rules aren't enough for me to deduce the most
natural way to things, so examples help.



> > Also, would I stylistically be better off naming these functions
> > animal-eat and person-eat, i.e. with a class prefix, so as to avoid
> > possible name clashes?
>
> No. That's generally the wrong thing.

That's what I thought. There seems to be some tension between the
names produced by defstruct and the most "natural" accessor names
for classes. I'd started by naming everything with the full prefix,
but have been growing more and more dissatisfied with that.

> Over time, I've been gradually fixing all the FOO-NAME and BAR-NAME
> operators in my code to just be NAME, for example...

I first started wondering about some of these issues when I was working
on a package of generic string functions. I tried to rename
STRING:STRING-FIND to STRING:FIND and, since I had missed the shadowing
abilities of packages, ground to a halt.

Thanks,

--Johann

Chris Riesbeck

unread,
May 15, 2001, 1:30:31 PM5/15/01
to
In article <sfwpudb...@world.std.com>, Kent M Pitman
<pit...@world.std.com> wrote:

>Choosing a naming convention that is memorable is handy, though.
>It's tough because FIND is a verb while POSITION is a noun and

Actually, both words are nouns and verbs. FIND as noun
in code seems less likely than POSITION as verb.

>REVERSE is either a verb or an adjective.

or noun, e.g., "it's just the reverse."

Kent M Pitman

unread,
May 15, 2001, 2:00:30 PM5/15/01
to
Johann Hibschman <joh...@uclink.berkeley.edu> writes:

> In article <sfwr8xr...@world.std.com>, Kent M Pitman
> <pit...@world.std.com> wrote:
>

> ... There seems to be some tension between the


> names produced by defstruct and the most "natural" accessor names
> for classes. I'd started by naming everything with the full prefix,
> but have been growing more and more dissatisfied with that.

Yes, this is a historical issue. DEFSTRUCT goes way farther back in
time than does DEFCLASS, and before there were generics with methods,
defstruct's naming was needed to keep things straight. Even today,
when there could be a single method spanning multiple, disjoint parts
of the class hierarchy, some efficiency gain comes for structs from
asssuming a hierarchical type system and lack of redefinition, and
this efficiency aspect of structures is one reason they ahven't been
wholly phased out.

One thing to understand about Lisp is that its design has embraced
gradual change over time, usually by not phasing out the old features
just because new ones came along until they really subsume the old.
And it often offers multiple forms of functionality supporting various
expressional styles. Some criticize the language for the occasional
apparent design inconsistency this exposes, but then others appreciate
it for its stability, not breaking old programs just because new ways
come along. Years ago, the languaeg used to change about every monday
and it was painful to the extreme; at some point, we realized
stability was necessary to people building product. CL exists for
various reasons, but one was to address that issue.

Joel Ray Holveck

unread,
May 15, 2001, 6:11:43 PM5/15/01
to
> Many consider it an annoyance that FIND and friends are not generic.
> There were some good reasons for not making them be, but there are
> arguments on the other side as well. It's a lamentable situation
> either way.

Not to incite a war here, but what are some good reasons for the
status quo?

Thanks,
joelh

Kent M Pitman

unread,
May 15, 2001, 7:11:01 PM5/15/01
to

I wondered if anyone would pick up on that. :-)

When generic functions first came out, there wasn't a lot of experience
in writing them--not specifying methods for them, but figuring out how
to document them, etc. How to navigate the fine line between genericity
and overloading.

For example, suppose we make + be generic and then someone DOES do
(defun add (x y) (+ x y)). This used to be a reliable function that
would either add two numbers or signal an error, at least in safe mode.
People rely implicitly not just on the normal effect, but also on the
idea that it won't invite people to pass wrong arguments.

e.g., if you add that stupid
(defmethod + ((string1 sring) (string2 sring))
(concatenate 'string string1 string2))
thing that everyone seems to adore so much, how does that affect your
symbolic algebra system when someone accidentally goes to integrate a
string instead of a symbol? Probably the computation proceeds and the
result is goofy. Contrary to the opinions of programming newbies, not
all error messages are bad to get--sometimes they save you a lot of time
over having the computation proceed and produce wrong results, or worse,
wrong effects.

And you know that stupid programming question that always comes up in
FAQs, about "finding" a symbol "anywhere in a list, even if hidden by
parens"? I can see someone modifying FIND to look into multiple levels
of a list, probably thinking they are "helping" since the system version
didn't do this. And if not this, they'd find some other place they thought
the system was deficient and invent multiple incompatible ways for different
packages to "extend" the system functionality so that packages with
different such theories could no longer be loaded at the same time.

As more things become acceptable, programs will tend to proceed executing
past the conceptual point of error farther to some other point that someone
perhaps just didn't have time to make generic.

People have said this of Teco, for example, where every command is a
single letter and where to the unaccustomed, you'd think that meant
every text sequence is a valid program in the language. (In fact,
violated argument conventions cause things to trap in short order, but
you can still execute for a ways before you run into trouble.)

I call languages that err for very few reasons "dense" and languages that
err in many situations "sparse". There is some value to a sparse language
because it recognizes errors in a timely way and doesn't just turn good
data to bad at the point of error and then continue merrily on its way.

Also, there are patterns of usage that we needed more experience with
in order to do definitions of things right. There are sealing issues
that are needed in order to get good efficiency on some opoerators,
and we had not added any sealing primitives.

And then there are specificational issues like the relationship between
DESCRIBE and DESCRIBE-OBJECT, PRIN1 and PRINT-OBJECT. The question of
whether the function you call is the one you specialize, etc. Consider
the following bug that really took me by surprise when I first saw it back
in the days of the design of NIL (the New Implementation of Lisp) circa
1980. I'll write this in no particular dialect since I don't remember
the primitives available--just assume things mean waht they look like:

(defgeneric length (thing))

(defmethod length ((string string))
(string-length string))

(defmethod length ((empty null)) 0)

(defmethod length ((cons cons))
(+ 1 (length (cdr cons))))

(length '(a b c)) => 3 ;ok
(length "abc") => 3 ;ok
(length '(a b . "cde")) => 5 ;hmm

I'd prefer this last one signal an error. But specifying LENGTH in a way
that avoids this outcome is pretty tricky. You want the definition of the
defgeneric's purpose to be to describe a behavior so clearly that everyone
will be able to adhere, but what would you have written (before you saw
any of the methods) in such a way as to have avoided this.

The single effect of this one operator may seem trivial to you, but if you
made a whole language out of massively generic setups, my personal intuition
is that you'd get many such interactions and they would be very, very tricky
to isolate.

Also, people often talk about some functions as if they had no definition
when they do. e.g., EQUAL. People often talk about how they wish EQUAL
would be defined for classes. But EQUAL *is* defined on their class--they
just don't like the definition. They want to give it a *different* meaning.
That's not the same thing. We might add another functio, ==, as so many
other languages have done that is defined by "compares two objects in a way
not globally predictable or consistent but that makes the implementor of
one or both of the classes be probably-happy". Maybe there's a better way
to describe the function, but I've never seen anyone go to the trouble.
They just take a fuzzy function and hope that's enough. Even EQUALP is
fuzzy due to its' exposing which classes are based on structures and which
on standard-class, and that's trouble enough. A totally generic EQUAL would
lead to all sorts of unreliability of EQUAL and might break all kinds of
programs due to user-errors in specifying methods that previously could not
be broken.

Rob Warnock

unread,
May 16, 2001, 12:06:58 AM5/16/01
to
Kent M Pitman <pit...@world.std.com> wrote:
+---------------

| I call languages that err for very few reasons "dense" and languages that
| err in many situations "sparse". There is some value to a sparse language
| because it recognizes errors in a timely way and doesn't just turn good
| data to bad at the point of error and then continue merrily on its way.
+---------------

This is precisely why I prefer "sparse" command-line shell command sets --
because I frequently make the mouse-o blunder of accidentally pasting a
selection-buffer full of random text into a shell window. Oops!! Sparse
shell languages are (somewhat) less likely to (say) delete all your files.


-Rob

p.s. Actually, in the above case what I probably really want is a
large average Hamming distance between the shell language and the
things I typically select with the mouse. Since things I select
are typically either programs or plaintext, I guess that means I
want shell commands that look like *neither*! (Hmmm... And people
say that Unix commands are "unfriendly"... Maybe not!)

-----
Rob Warnock, 31-2-510 rp...@sgi.com
SGI Network Engineering <URL:http://reality.sgi.com/rpw3/>
1600 Amphitheatre Pkwy. Phone: 650-933-1673
Mountain View, CA 94043 PP-ASEL-IA

Kent M Pitman

unread,
May 16, 2001, 4:50:23 AM5/16/01
to
rp...@rigden.engr.sgi.com (Rob Warnock) writes:

> Kent M Pitman <pit...@world.std.com> wrote:
> +---------------
> | I call languages that err for very few reasons "dense" and languages that
> | err in many situations "sparse". There is some value to a sparse language
> | because it recognizes errors in a timely way and doesn't just turn good
> | data to bad at the point of error and then continue merrily on its way.
> +---------------
>
> This is precisely why I prefer "sparse" command-line shell command sets --
> because I frequently make the mouse-o blunder of accidentally pasting a
> selection-buffer full of random text into a shell window. Oops!! Sparse
> shell languages are (somewhat) less likely to (say) delete all your files.

Yes, this is one reason that machine languages usually have "0" be an
illegal opcode, btw. It's assumed that data areas are full of 0's and
if you accidentally execute them, you will have some reason to stop.

> p.s. Actually, in the above case what I probably really want is a
> large average Hamming distance between the shell language and the
> things I typically select with the mouse. Since things I select
> are typically either programs or plaintext, I guess that means I
> want shell commands that look like *neither*! (Hmmm... And people
> say that Unix commands are "unfriendly"... Maybe not!)

Interesting.

0 new messages