Re: Seeking computer-programming job (Sunnyvale, CA)

S

Series Expansion

You already saw them. The only thing is that you don't understand them
because you don't understand Lisp.

I still have yet to see any. Certainly the above-quoted personal
attack fails to impress.
 
S

Series Expansion

ConteXt, before you flame me again for writing wrong English.

(I note the irony of your making this remark in the context of
correcting a spelling error that happens to be located in one of
*your* flames.)

I have not flamed you much, if at all, compared to your flamage of me,
and likewise, my arguments have been valid reasoning based on sound
premises, rather than largely consisting of exhortations, expletives,
exclamations, name-calling, denials, and bald assertions unsupported
by evidence or logic.

Based on this last, particularly, one suspects you had particular
difficulty in school with that subset of math teachers who grade a
flat zero on any question where the student didn't show his work, even
when the answer he'd arrived at was correct.
 
S

Series Expansion

He meant that

I am quite certain that Pascal is capable of speaking for himself.
a C macro is so much different from a Lisp macro that,
to understand a Lisp macro, you need not to take any knowledge you
already have using C macros.

This is clearly incorrect. They are still both macros, which means
that a certain intersection of their natures exists. Particularly,
those things that follow unassailably from the fundamental definition
of "macro", independently of implementation details, will lie within
that intersection, and it is those things that form the basis of my
macro-related arguments here.
 
S

Series Expansion

[...]
It's strange to be told, repeatedly, that things I do routinely,
without a great deal of difficulty or aggravation, are in fact
ridiculously hard and painful.
Real debugging or some sort of cargo-cult debugging, going through the
motions and having faith that it will have the intended effect?
Real debugging. Lisp macros are a good deal less arcane than you seem
to think; the ones you write 95% of the time are really just
straightforward Lisp functions that act on a tree made up of conses.
Except that macros lack the natural encapsulation barrier that
surrounds functions, as explained elsethread. With all the
consequences for debugging straightforwardness that that implies.

I don't understand this....  Would you care to explain?  Debugging
macros implies debugging an AST rewriting process (something you do
not have at hand with the C preprocessor).  In what way you are
"breaking the 'natural encapsulation' barrier"?

The behavior of function calls depends sensitively on the semantics of
the function's code, but not on its detailed implementation. One
example I'd previously used was that a function can be reimplemented
to change x + x to 2*x without altering its behavior, save possibly
for its speed of execution.

However, the same change in a macro, where x is one of its formal
parameters, causes a change in the semantics at any call site where
the corresponding actual parameter is an expression with side effects.

Furthermore, changing the names of local variables in a function, in
such a manner that the semantics of the function are unaltered, has no
effect whatsoever on its behavior when called (except for speed of
execution in the case of the most simple-minded and primitive
interpreters, where the longer the name the slower it runs). For
example, changing a variable named "foo" to "bar" throughout a
function that does not contain or use from an enclosing scope any pre-
existing variable named "bar".

The same change in a macro will cause changes in its behavior at call
sites with a pre-existing variable named "foo" or "bar" (un-capturing
the one and capturing the other). If the variable is declared inside a
nested scope, such as a { } pair in C, then the effects are subtler:
changes only occur at call sites that have such a pre-existing
variable *and use it in one of the expressions that is an argument to
the macro*. This time the effects result from the variable in the
nested scope hiding/unhiding the variable existing at the call site;
the hiding of this variable has no ill effects unless it is accessed
within the nested scope, which will only happen if it's used in one of
the macro's argument expressions.

This is what I mean by a broken encapsulation barrier: function call
sites are insulated from being affected by certain changes within
function bodies, and furthermore macro call sites are not insulated
from corresponding changes within macro bodies.

It is analogous to, though not identical with, the encapsulation
barrier familiar from OO theory, where changing implementation details
of a well-written class that don't change the semantics of its public
methods will not break code anywhere else in the project.
Unfortunately, it is quite evident that changing implementation
details of a macro, even a well-written one, will always have the
potential to break code elsewhere in the project.
 
A

Adlai

I am quite certain that Pascal is capable of speaking for himself.


This is clearly incorrect. They are still both macros, which means
that a certain intersection of their natures exists. Particularly,
those things that follow unassailably from the fundamental definition
of "macro", independently of implementation details, will lie within
that intersection, and it is those things that form the basis of my
macro-related arguments here.


Series, I wish I had the time to respond in detail to each of your
posts and provide you with material so you could keep on lighting fire
to your pink bunny boxers. However, time is limited, and I have a busy
day ahead. I look forward to reading your inspired verbal diarrhea
when I return from my LIFE at the end of the day. With some amount of
good fortune, there will be another 15 minutes of pure joy waiting.

I'm loving it.


- Adlai
 
S

Series Expansion

I've already answered you.

You had indicated that free implementations of CL itself existed
(though I remain unaware of any Windows ones), but I don't recall
seeing anything about their library feature-coverage until now.

[snip encouraging information regarding library coverage]
Yet this is precisely what happens when you use any kind of XML-based
configuration in Java and other languages.

I have not claimed that those kludges are superior; indeed they
clearly are not. What is truly needed is going to be quite different
from either.
Any decently-sized enterprise application will use at least some
of them, and probably others. All of these files refer (using
strings!) to names of classes, or even properties and methods of those
classes, and combine them *without* any kind of static type checking,
since XML is not considered to be source code and thus not compiled.

Perhaps the solution is a standardized script interpreter in Java that
can call into Java and that inherits Java's type system; such
configuration files could then be replaced by scripts that this
interpreter would run. The interpreter would report any type errors in
the scripts immediately on parsing them, so the scripts could be
checked by running a unit test that simply invoked the interpreter
class's "load script" function without calling any entry points within
the script.

Of course, you'd get the reverse problem, no type checking of Java
calls into these scripts, but it's a much smaller problem since the
typical case would replace a long XML file with many Java bindings
(unchecked) and a call to an XML interpreting function to a long
script with many Java bindings (checked) and a call to a
"configure_server" entry point (unchecked). One unchecked call instead
of many. If it was specifically for this sort of configuration task,
it could even be designed so that scripts just had one entry point
with no arguments (from Java) and the call pattern was just
Interpreter i = Interpreter.load(scriptFile); i.run(); and nothing at
all unchecked now.

Then again, I don't see why there isn't a tool to type-check the XML
file against the Java codebase, or use of unit tests to use the XML in
the Java code in a mock server environment to reveal any problems pre-
deployment.
If you say that programmers should get rid of these non-statically-
typed tools and always use statically-typed Java for everything,
that's fine

I don't.
So I'm just saying that what in Spring you write as

<bean id="someObject" class="com.mypackage.MyClass">
  <property name="someProperty" ref="someOtherObject" />
</bean>

I don't see why tools can't easily type-check this, for instance by
checking that com.mypackage.MyClass exists, has the appropriate
getters and setters, and these have the appropriate type (the class
named in the "class=" attribute of the bean tag with
"id=someOtherObject").

In Lisp, you'll have no types at all on any of this stuff, so while it
may not be worse it isn't better either.
(defvar *some-object*
  (make-instance 'my-package:my-class
                 :some-property *some-other-object*))

and *compile* and load the file with this code *at runtime*, getting
warnings or errors if you have made mistakes.

There's no reason that the Java code that processes the XML files
can't likewise generate warnings or errors at runtime. Indeed, I
expect it must, throwing various reflection exceptions like
NoSuchMethodError, depending on the exact nature of the problem.
I know JUnit and regularly use it - for testing Java code. I'm not
aware of how JUnit could test fragments of XML.

I was responding to the erroneous implication that something in Java
precluded testing single functions in isolation.

Regarding XML, see above -- if one had JUnit tests for the system as a
whole (the Java AND the XML) these could easily include checking that
the XML works.

More generally, I don't see a timing advantage to the error messages
on either side here, let alone on Lisp's. While technically the Lisp
errors occur "at compile time", this is only because it compiles the
bean info file when it loads it whereas the Java analogue does not
compile the XML file. Both will spit out corresponding errors at the
same point: when they get around to loading the corresponding bean
info files. Neither gives earlier warning of trouble than the other.
 
S

Series Expansion

As you can see, Lew has nothing worthwhile to say whatsoever in the
way of arguments either for or against Lisp, merely a vitriolic
outpouring of namecalling so foul as to inspire me to wash my hands
after reading it due to a certain open question regarding exactly
which orifice oozed forth the reeking substance of it.
Yes, don't judge a language by its trolls - we have some of them in
comp.lang.lisp, too.

We've noticed.
 At the moment, we are in the lucky situation that Xah Lee and Jon
Harrop are taking a rest

I have seen several of Xah Lee's threads in comp.lang.java.programmer,
and remain unconvinced that he's a troll, at least in the classic
sense. Rather he seems to use Usenet as a publication platform for
lengthy tracts, and a promotional vehicle for his Web site. That he
doesn't seem to use automated posting or large Breidbart indices, and
sometimes lingers to discuss at least briefly some of the replies,
causes him to also fail to qualify as a spammer.

I am not familiar with Jon Harrop. He does not seem to post to
comp.lang.java.programmer.
but the Maas troll who started this thread is still active.

I'm also unconvinced that he's a troll. He's disturbed, if you ask me.
P.S.: I think we can also be quite sure that there are no Lisp or Java
"gods" present in this thread.

Certainly nobody in this thread has impressed me as having that kind
of status; in the other direction, I suspect several to be under legal
drinking age.

The closest thing to a Java "god" in comp.lang.java.programmer that we
have right now might be Patricia Shanahan. Knowledge, wisdom,
intelligence, and a tendency to stay out of the sordid business of
personal attacks at least most of the time. There are several other
people of note, some quite knowledgeable, but most of these stand out
primarily by being loudmouthed, argumentative boors. You've met one. I
assume that merely being opinionated a vocal does not a "god" make
you.

Those that actually designed Java and those that are highly placed in
Sun Microsystems seem not to hang out in comp.lang.java.programmer.

Meanwhile I theorize that some of the Lisp vs. Java animosity might be
explained as a kind of sublimated emacs vs. vi hostility. Whereas
there seems to be a close association between Lisp and emacs, and the
latter uses a dialect of the former as its scripting language, one of
the creators of Java was also the principal developer of vi some
decades ago. On the other hand, plenty of Java developers use neither
of the old Unix editors, preferring more modern tools. This leads to
Eclipse vs. NetBeans fights. :)
 
S

Series Expansion

You're complaining that macros can do something that functions can do
too?

No; functions generally cannot do that. For example, in C:

#include <stdio.h>
int foo (int x) { return 0; }
#define foo(x) x
int main (void) { printf("%d",foo(1)); }

-> 1

#include <stdio.h>
int foo (int x) { return 0; }
int foo (int x) { return x; }
int main (void) { printf("%d",foo(1)); }

-> duplicate symbol error

Java likewise won't allow silently replacing methods or classes, save
by replacing their .class or .jar files rather than simply adding code
somewhere. Though Java lacks macros.
You might want to explain this "lack of encapsulation barrier" stuff

Already did, at least twice. I don't feel like doing it a third time.
so we can tell you specifically how wrong you are this time.

If my doing it a third time would be "rebutted" with ad hominem
arguments, then I am certainly not doing it a third time, since
clearly it would be a waste of my time instead of leading to
productive debate.
 
S

Series Expansion

The language forbids to define methods of standard generic functions
on standard classes.

That does not remove the problem, only reduce it somewhat. Replace
system classes and generic functions with ones from a popular third
party library, for which further add-on libraries get developed, and
we're back to square 1.

Your statement does perplex in another way: it seems to be impossible,
given that the object system under discussion is itself a library and
not an integral part of Lisp itself. That is, whereas the syntax,
semantics, and interpretation of Java source and JVM bytecode is shot
through with class, object, method, and the like, the syntax,
semantics, and interpretation of List source and Lisp bytecode is shot
through with cons cells and very little else. This seems to preclude
the compiler or interpreter from making any assumptions about object
systems or any other structures that users might implement on top of
the bare bones of the language, where there are many possible
implementations. Even if one has become standardized upon.

Of course, tools external to the language core itself could exist that
"lint" CLOS code or similarly for certain kinds of CLOS no-nos;
perhaps you mean that one of these will complain about such code, and
thereby prevent problems developing quietly from additions to standard
generic functions?
Next if it's the name of the generic-function you're interested in,
you can always shadow it it and use your own symbol of same name

Variable and method hiding is a fruitful source of headaches, in my
experience.
But at least, with Lisp you can indeed develop big software with less
developers, smaller teams than with other programming languages.

If true, that is a mitigating factor, but of unknown and probably
small magnitude.
Therefore you don't.

Don't get me wrong. You can do some pretty evil things in Java, too.
(It lacks goto but allows global variables. Lots of fun to be had
calling polymorphic methods from constructors of non-final classes,
writing static initializers with side-effects, and things like that.)
Unfortunately, it sounds like to do many of the more powerful things
in Lisp, you are forced to do evil things, from mildly tainted
(modifying generic functions outside your fiefdom) to unavoidably
hazardous (using macros) and degrees in-between.
Lisp language designers don't think lisp programmers are dumb.

Unfortunately, the smartest programmer in the world cannot make a
macro that uses an argument multiple times and simultaneously avoids
all four of: multiple evaluation of that argument, variable capture,
variable hiding, and use of a global variable. In any language,
regardless of details of the macro implementation. He might as well
try to write an algorithm that answers the halting problem for any
input program. It is simply not logically possible for him to succeed.
 
S

Series Expansion

Not at all.

Responding by simply calling your opponent a liar is rarely a viable
strategy for either a) winning a debate or b) making friends and
influencing people.

Particularly when anyone of normal intelligence would have recognized
the quoted passage as intentionally hyperbolic.
You are not the one to say whether they'd be obsolete or not, only
their users.

How do you know I'm not one of the users of one of these applications?

Regardless, Lisp appears to have been designed for a simple line-
oriented-terminal model of interaction, much like bare-bones ANSI C,
actually, which requires third-party libraries to even do curses-type
stuff, let alone graphics and mouse support. Unlike C, it seems
difficult for such libraries to exist when Lisp, unlike C, compiles to
bytecode. Certainly third-party Java libraries cannot, unless they use
JNI, directly access hardware and thereby attain capabilities
involving interfacing with the hardware or the host OS that weren't
built into the JVM or the standard libraries. And I have not heard of
any Lisp facility analogous to JNI. So unless the LVM (or whatever you
want to call it) provides a particular form of host-system interface,
it is apparently unavailable to programs.

In my browsings around the net, the free Lisp implementations I've
come across seem to all be line-oriented. While it's possible that
I've missed something, it looks like the facilities required to create
a more capable UI are unavailable outside of expensive commercial
implementations.

However, even if those "programs you wrote twenty years ago" run on
such a commercial implementation, they can't use graphics facilities
or the like that did not yet exist twenty years ago. Their user
interfaces will be vintage 1989 user interfaces, which tended at best
to be curses-like ones.
And corporations may have something else to do, and something else to
finance, than to pay java programmers to follow the fashion of the day
in GUI for their mission critical software.

It is not a matter of fashion, but of ergonomics. Making the software
easier to interact with could enormously boost productivity, unless
it's an infrequently-used batch-mode program or something similar.
Moreover, improving the software's ergonomics could reduce error rates
in its use. Ergonomic improvements in other aspects of workplace
technology have had all of the following effects in various times and
places:
* Increased productivity
* Reduced workplace accidents
* Improved job satisfaction
* Reduced the cost of training new hires
* Boosted comfort, in cases affecting posture and physical
activities of employees, and reduced stress, physical
strain, and repetitive stress injuries
and more.
 
M

Martin Gregorie

Software development does not necessarily require much computer power.
An old 486 with DOS 6.22 and DJGPP for C programming does not seem slow.
The editor may seem a bit primitive, but then more thinking and less
typing is usually a good thing.
Appropriate software can help too - an 866 MHz P3 with 256 MB RAM
wouldn't have a hope in hell of running Windows XP or later, but is OK
running most current Linuxes including the graphical desk top. Admittedly
having 512 Mb RAM is better but isn't necessary for a Linux development
box.

FWIW I have just such a machine that's currently running Fedora 8 at a
perfectly acceptable speed. Its my main development box for C and Java,
which is done alongside a variety of servers (Postfix [mail], Apache [web
server], Postgres [RDBMS] and with Seti@Home in the background to soak up
unused cycles).
 
A

Alessio Stalla

Unfortunately, the smartest programmer in the world cannot make a
macro that uses an argument multiple times and simultaneously avoids
all four of: multiple evaluation of that argument, variable capture,
variable hiding, and use of a global variable. In any language,
regardless of details of the macro implementation. He might as well
try to write an algorithm that answers the halting problem for any
input program. It is simply not logically possible for him to succeed.

Really? Watch this:

(defmacro logically-impossible-macro (arg)
(let ((generated-variable (gensym)))
`(let ((,generated-variable ,arg))
(list "Using generated symbol: " ',generated-variable
"Multiple Evaluation?" (not (eql ,generated-
variable ,generated-variable))
"Global variable?" (boundp ',generated-variable)
"Variable hiding?" (setq ,generated-variable 42)))))

---- example usage ---

CL-USER 2 > (defvar generated-variable 0)
GENERATED-VARIABLE

CL-USER 3 > generated-variable
0

CL-USER 4 > (LOGICALLY-IMPOSSIBLE-MACRO (incf generated-variable))
("Using generated symbol: " #:G807 "Multiple Evaluation?" NIL "Global
variable?" NIL "Variable hiding?" 42)

CL-USER 5 > generated-variable
1

---------------

incf is like ++ in Java. Defvar defines and initializes a global
variable.
I have purposedly used the name "generated-variable" for my global
variable, without using the naming convention of *global-variable-
name*, to show how NO variable hiding happens: although I set the
value of generated-variable to 42 in the macro, the global variable
was not modified. The trick is using a freshly-generated symbol
guaranteed to be unique, a so-called gensym (the symbol named #:G807
in my example), for the temporary variable's name. Do you understand
now?

Alessio
 
T

Thomas A. Russ

Series Expansion said:
I'm not the one doing the flaming here at all.

I'll grant that you are not flaming. You are just blathering. You are
just spouting idiotic comments about technology that you clearly do not
understand.
I just explained why the package system won't. Adding new classes in
their own packages? No problem, the package system can distinguish
foo.String from bar.String. Adding new methods to an existing class,
say foo.String? Uh-oh. Is that baz's foo.String.doIt() or quux's
foo.String.doIt()? They have the same method name, are methods of
classes with the same name, and the classes are in the same package.
As far as the compiler is concerned, they are the same. The package
system cannot distinguish them unless we add another layer of
namespacing, this time INSIDE classes, and have foo.String.baz.doIt()
and foo.String.quux.doIt() instead of just foo.String.doIt() as the
fully-qualified names. And now we're deep in migraine-headache
territory, without oar or compass...

Well, the above paragraph is prima facie evidence that you have a
profound ignorance of how the Lisp package system works. You also have
a profound ignorance of how the Lisp object system works. And taken
together, those sources of ignorance lead you to raise objections that
are absolutely incorrect.

First of all, methods don't belong to classes. Period.
Second of all, classes don't establish any sort of namepsace. Period.

The only way in Lisp for you to have "classes of the same name" is for
them to be exactly the same class, as in EQ classes. To put this into
Java terms for you, the confusion you are imagining would be akin to
saying that one could have two classses java.lang.String and
java.lang.String which are different, and thus confusable. You can't,
since they are the same classes.

So the Lisp package system is quite capable of easily distinguishing
between different generic functions when you seek to invoke them, or add
methods to them. In fact, adding new methods to existing generic
functions is one of the great strengths of the Common Lisp language.
And it all works fine, and has done so ever since the Common Lisp
specification was formulated in 1994. In fact, it was never a problem
even before the specification was created, so there has been more than
15 years of work that has, amazingly enough, never run into the problem
that you in your lack of knowledge so blithely assert.
 
S

Scott Burson

I'll grant that you are not flaming.  You are just blathering.  You are
just spouting idiotic comments about technology that you clearly do not
understand.

I prefer not to participate in Usenet pissing matches, but I sometimes
get my jollies by reading along. In this case I gotta say, with
Series the laughs just never stop.

I fear you're wasting your breath, though.

-- Scott
 
T

Thomas A. Russ

Seamus MacRae said:
Java can do this (return an object or null), and java.util.Map.get()
does it and is in the standard library.

Um, how does this work if you want the Java method to return a literal
such as int or double? I guess you are then forced to wrap the return
type in the corresponding Integer or Double, so that you have a safe
null value you can return?
 
T

Thomas A. Russ

I V said:
I'm not exactly sure when the first windowed version of Emacs was
developed, but GNU Emacs had a windowed version in 1987:

http://www.gnu.org/bulletins/bull2.txt

Emacs has been a windowed program for over 20 years.

Actually, it's really closing in on 30 years.

The zmacs variant was a windowed program since sometime around 1980.
This was used in the Lisp machine, which was also one of the first
single-user workstation designs. It was also one of the early uses of
bit-mapped (as opposed to character or vector) displays.
 
L

Larry Coleman

Oh, shit. I think you guys may actually be dealing with someone with a
9th-dan black belt in usenet-fu here. Do you see how he subtly, but
quite definitely, retaliates for your earlier insulting comparison of
his Java code to vomit by doing the same to your Lisp code here?

No matter. I'm outta here before it all hits the fan.

Seamus MacRae and Series Expansion are proving themselves to be
grandmasters of trolling. The Troll-o-Matic will have to be updated to
reflect their expert techniques.

And has anyone else noticed that they are never both present at the
same time? Just a thought.
 
T

Thomas A. Russ

[We'll ignore the fact that + in Common Lisp is not a generic function,
but rather a built-in function that does coercion. We'll also ignore
the fact that complex numbers are built-in to Common Lisp, since
neither fact affects the larger issue here.]
Now you can see where the problem will show up. If I want to add a
Complex noun, now I have to add a plus(Complex, Complex) to plus. Which
means I have to modify something in the system package. Uh-oh!

Well, this paragraph is great up until you get to "Uh-oh!".

There is not "Uh-oh!" in Common Lisp at this point. In fact, that it
precisely the point of all of this. You can do this. It is natural.
It is not a problem. You just do it.
It all boils down to which programmers will be doing more often: adding
new nouns which may be used with already-existing verbs, or adding new
verbs which may be used with already-existing nouns.

Well, why not use a system that makes either one just as easy? Then it
doesn't matter which is more frequent, because either option is handled
exactly the same way. That leads to a nicer, more uniform way of
operating with the language, so that the entire language model is easier
to understand.
Adding new nouns which are used only with new verbs is not a problem in
either case.
Right.

Adding new nouns which may be used with already-existing verbs is not a
problem if namespaces contain nouns, which contain implementations per
supported verb. But it is a problem if namespaces contain verbs, which
contain implementations per supported noun.

Why is that a problem?

BTW, in Common Lisp, namespaces are not tied to classes at all. They
are their own separate entity, so any effect based on namespaces is
equally easy regardless of whether you are talking about new classes,
new generic functions or new methods for existing generic functions.
Adding new verbs which may be used with already-existing nouns is not a
problem if namespaces contain verbs, which contain implementations per
supported noun. But it is a problem if namespaces contain nouns, which
contain implementations per supported verb.

Right. So here is a class of problem where one particular object system
gets in your way. See, for example, my nice hammer and picnic blanket
analogy elsewhere in this thread.
So, if new nouns with existing verbs is more common, Java's method is
better. If new verbs with existing nouns is more common, Lisp's method
is better. (Leaving static vs. dynamic typing entirely alone here and
considering only the order of scoping of nouns and verbs within
namespaces.) Doing the "wrong" one in either language will cause
headaches unless there's a way to namespace separately by noun and verb,
which would cause its own inherent variety of headaches instead.

The error in this analysis is conflating the notion of a namespace with
that of a class or function/method. In Java there is such a conflation,
because methods are associated with classes and resolved relative to
them. This is not the case in Common Lisp, so there isn't any
difference from the namespace perspective between adding either one.

One uniform mechanism that handles both cases with equal ease. That is
one reason I think the Common Lisp object model is superior. Another is
multiple-dispatch, but that's a completely different discussion.
My own experience tells me that new nouns with existing verbs is more
common. I quite often want to define a new Java class that has state. I
much less often wish for an existing Java class to have a method I've
never heard of before.

Well, part of that may be conditioning, since you can't really have the
latter. So you learn to do with out it. Well, actually that's perhaps
a bit strong. Typically the solution to this is to either write wrapper
classes or interfaces to add the new functionality or else to use static
methods on some utility class so you can write methods that affect
classes to which you don't have source code access.
The workaround also isn't usually that bad: create a utility class with
a static method to do the manipulation. It can't be polymorphic or use
the object's private state directly, but the latter is for the best and
the former, while annoying, isn't usually a show-stopper.

Well, the workaround does have the minor problem that you don't get
dynamic dispatch for the static methods. So if you want to have a
hierarchy of classes with different methods, you lose the benefits of
dynamic dispatch and have to manage that yourself. That sounds to me to
be a bit more tedious and potentially error-prone.
The Lisp way around would present problems.

And yet, oddly enough, in practice there don't seem to be any. It works
just fine.
On the rare occasion I
wanted to augment an existing class with new behavior it would be easy:
define my own verb in my own namespace and set up somehow a polymorphic
dispatch on object type. On the much more frequent occasion I wanted to
add a new noun, I'd often be forced to change verbs that lived in
pre-existing namespaces, and maybe even in more than one namespace; the
code for my new noun would be scattered all over the codebase AND the
namespaces within the system, rather than in exactly one place in each.

First of all, you don't "change the verb". You simply add a method.

And there is absolutely no reason that the code for your new class has
to be scattered anywhere. You can, if the organization makes the most
sense for your application, put the method definitions IN THE SAME FILE
as the class definition. If it makes more sense to organize around the
generic function instead, then you can. Or you can even mix it.

The


No ouch. Simply a misunderstanding of how Common Lisp programs are
organized. This debate really puts you at a bit of a disadvantage,
since the Common Lisp advocates have programmed a lot more in Java than
you have in Common Lisp. And it shows, because lots of misconceptions
about "how things must be" crop up.

That is a result of hearing about a particular lisp feature and then
applying an incorrect noton about "how it must be", based only on your
experience programming in Java. If you wish to broaden your set of
programming skills and increase the intellectual understanding of the
range of design options in programming languages, you would do well to
try out some of the other languages that work differently. One nice
starting place would be Abelson & Sussman's _Structure and
Interpretation of Programming Languages_.
There's also going to be big differences in polymorphism. With an object
oriented system, nouns can be subtypes of other nouns, and verb behavior
can be inherited, with or without modification. Dispatch is based on the
run-time-type of the noun, and adding a new polymorphic type is easy. In
Java, suppose there was an Addable interface specifying the plus method,
and Integer, Float, and Double implemented it. If I created my Complex
class and implemented Addable, code that did generic sums over Addables
would automatically also work with Complex now. I wouldn't have to make
any changes outside the Complex class.

Well, Common Lisp has its own object oriented system. It just works
differently, in both gross and subtle ways that I don't think you are
familiar with.

For example, you write "Dispatch is based on teh run-time-type of THE
noun." That is because you have an assumption that there can only be ONE
object whose run-time-type determines the dispatch. But in Common Lisp
that is not the case. Any combination of the required arguments can be
used to select the actual method to run for a particular generic
function. So, you get an even more flexible polympophism method.

I also don't think you want to try to argue flexibility of method
dispatch at this point. Common Lisp has multiple-argument dynamic
dispatch that also includes dispatching and defining methods on literal
data types.

As for adding a new type, it would be just as easy in Common Lisp. In a
single source file you would provide the class definition for Complex
and then provide a method definition for the "plus" generic function.
You don't need to make any changes to any other location. You can put
this all in the same source file.

Furthermore, you could also define methods that handle the addition of a
complex number to a Double. How would you go about doing that in Java?
You would have to change all of the Integer, Float and Double classes
because you can't arrange to put the new method just in the Complex
class.
With Lisp, I'd need to change the system namespace's plus verb's
dispatch table manually so that it knew about my Complex class, on the
other hand.

Say what? Do you have any clue how Lisp actually works?

You don't change dispatch tables manually. You just write definitions.
Unless you consider defining new classes in Java to be "manually
changing the system's type hierarchy". You really would be a more
credible debate partner if you didn't keep saying things that betray a
complete ignorance of how things work.
Both problems in one. In fact, every combination of noun and
verb in dynamic dispatch needs to be explicitly specified
somewhere. From the sounds of it, I couldn't just say "Complex is a type
of Number" in Lisp and have the compiler automatically know where to
dispatch plus, minus, times, and dividedBy;

Um, and if you implement a interface in Java, suddenly all of the
methods are automatically specialized for your new class without you
having to write implementations for them? Really?

In lisp, you could say something like that and any more general methods
would automatically be available. If you want specialized handling of
the type, then you have to write method bodies for them.
I'd have to edit four
separate dispatch tables in four separate places, AND define (hopefully
all in one final, fifth place) my Complex implementations of these that
the new dispatch table entries would point to.

No, all of the bookkeeping is handled by the language. Just like you
don't need to edit any dispatch tables in Java. What makes you think
you as the programmer need to do it in Lisp? This is pure ignorance of
how things work.

You can do all definitions in contiguous places in a single source file
and you don't have to worry about any of the internal details. That's
why they are internal details.

There are no dispatch tables to edit. There are no separate places to
do anything. You can do it all in one place.

With Java I'd just have
to define the implementations, naming them correctly, and stick
"implements Number" somewhere and away I'd go.

Which is exactly analogous to Common Lisp (assuming CL actually needed
to implement Complex -- which it doesn't, since it's already built-in....)

The structure of the file would be something like this:

(defclass complex (number)
((real-part :type number)
(imaginary-part :type number :init-form 0)))

(defmethod plus ((x complex) (y complex))
...)
(defmethod plus ((x double) (y complex))
...) ;; How do you do this one in Java???


(defmethod multiply ((x complex) (y complex))
...)

etc.

This all goes in one file.


That's the same thing isn't it? He says "private", you say "won't be
exported"; it looks the same to me.

But it isn't.

At each place where it arises.

This can happen in Java too, if the same piece of code uses two
different classes with the same unqualified name. You can end up with
code littered with "java.util.Date" and "javax.sql.Date" for instance in
some types of enterprise code. It's god-awful. All those repeated
"java.util." and "javax.sql." prefixes add up to quite a lot of
boilerplate.

Fortunately, it's rare to get name clashes between different peoples'
nouns and still need to intersperse both in one bit of code. It's much
more common with verbs:

someIOStream.close();
aDoor.close();
aPort.close();
aSocket.close();
aTransaction.close();
if (difference(pointA, pointB).close()) doSomething();

I'd hate to have to fully qualify all my "close"s, or "open"s, or
"free"s, or "release"s, or "next"s, or "remove"s, or "equals"s, instead
of the correct one being inferred from the type of the expression to the
left of it.

Well, we think that there is a fundamental difference between different
sorts of close and prefer to make sure they have different names. That
certainly helps out when one ends up making a hybrid class using true
multiple inheritance, where you have to know the difference between the
different CLOSE methods one inherits.

So, there would perhaps be two or three differently named CLOSE
operations, as distinguished by their namespace. And you could have
methods for several of them on the same object. Furthermore, you could
also have general methods (defined on the universal type T, roughly
equivalent to Object in Java), which would then handle the operation for
all of those objects to which it may not apply. Or else you could just
let the standard error handling operate on it.

But it is a different way of seeing and operating, because it is a
different paradigm for doing object-oriented programming. You may or
may not like it, but that would only be an informed choice if you
actually tried working with both systems.

In actual practice, you would only need to use fully-qualified names in
the same type of circumstance that you need fully-qualified names in
Java: When there is an ambiguity in the "short names" in the namespace
that you are operating in.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,436
Messages
2,571,696
Members
48,796
Latest member
Greg L.
Top