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

Javugh

4 views
Skip to first unread message

Jeff Shrager

unread,
Dec 19, 1996, 3:00:00 AM12/19/96
to

Since there obviously isn't enough controversy on this list.... :)

A number of folks here have said (w/o giving examples) that Java is
somehow significantly closer to lisp than C++ (Of course, moving
finitely closer to zero from negative infinity still leaves you at
negative infinity, but I'll leave that aside for the moment.) Based
upon this opinion, I've gone off and skimmed a little Java. Now, I'll
admit that I haven't actually WRITTEN any yet, but I can't see offhand
what makes Java any more interesting than C or C++, or any other
random non-lisp language to a lisper. Okay, so someone cleaned up the
class system slightly. That's nice, I suppose, if one cares about
OOP'ing, but there doesn't seem to be much to recommend Java from the
standpoint of list processing, just to name an often-overlooked small
features of the LISt Processor. (That is, e.g., processing atomic
items in a natural and flexible data structure.)

However, it's between possible and likely that I'm missing something,
since I'm not actually a Java programmer, so could someone who
actually uses Java please enlighten me in a concrete way by, for
example, posting a Java equivalent (with commentary!!) of something
truly lispy, like, um, how about a classic list pattern matcher, you
know:

(list-match '(a ((s d) (x y)) (x y) s) '(a (?1 d) ?2) ?2 ?1)
-> ((?1 . s) (?2 x y)) ; I hope I got this right -- if not, you know
; what I mean anyhow
[or nil if it fails]

Thanks very much.

Cheers,
'Jeff


William Annis

unread,
Dec 19, 1996, 3:00:00 AM12/19/96
to

Jeff Shrager (shr...@neurocog.lrdc.pitt.edu) wrote:
: Since there obviously isn't enough controversy on this list.... :)

:)

: A number of folks here have said (w/o giving examples) that Java is
: somehow significantly closer to lisp than C++ (Of course, moving
: finitely closer to zero from negative infinity still leaves you at
: negative infinity, but I'll leave that aside for the moment.)

The main things that Java borrows from Lisp are:

1) Garbage collection.
2) Exception handling (via C++, probably).
3) The interfaces business is a bit like the
"mixin" concept of Flavors. (In case you didn't
read about these, when interfaces are "implemented"
by a class definition you are expected to define
certain methods. This avoids the stickiness of
multiple inheritance but guarantees that
certain functionality will exist for you.)

I'm not sure that I'd say Java is "significantly" closer to
Lisp than C++, though.

I expect books and articles on Java to start nagging at people
about excessive "consing", ie garbage creation, soon. Quite a lot of
Java looks like a Lisp novice's code, at least with respect to
torturing the garbage collector.

: However, it's between possible and likely that I'm missing something,


: since I'm not actually a Java programmer, so could someone who
: actually uses Java please enlighten me in a concrete way by, for
: example, posting a Java equivalent (with commentary!!) of something
: truly lispy, like, um, how about a classic list pattern matcher, you
: know:

: (list-match '(a ((s d) (x y)) (x y) s) '(a (?1 d) ?2) ?2 ?1)
: -> ((?1 . s) (?2 x y)) ; I hope I got this right -- if not, you know
: ; what I mean anyhow
: [or nil if it fails]

Symbolic computation is NOT one of those lispy things Java
borrowed. Doing the matching above would take some work. Of course,
doing it in lisp is also non-trivial, which is why it figures nicely in so
many Lisp textbooks.

I was really into Java a few months ago. I got over it. I still
like the language, though that may be because it's making me money. :)
If I had my way, however, Java would support functions/methods as first
class objects. That would make a number of things quite nice, as well
as fixing the very odd little way threading is handled. Even C can
fake this with pointers to functions. Doing this might offend OOPy
sensibilities, though, so I'm not going to hold my breath.

Hope this helps a little. Marty Hall's home page has a lot
of stuff on both Lisp and Java:
http://www.apl.jhu.edu/~hall/
He has a nice discussion of the whole mixin thing, too:
http://www.apl.jhu.edu/~hall/java/mixins.text


--
William S. Annis Programmer
Ofc: 608 262-6163 wil...@neurosim.wisc.edu
Department of Neurology Neurosimulation Lab


Jeff Shrager

unread,
Dec 19, 1996, 3:00:00 AM12/19/96
to

: Symbolic computation is NOT one of those lispy things Java

: borrowed. Doing the matching above would take some work. Of course,
: doing it in lisp is also non-trivial, which is why it figures nicely in so
: many Lisp textbooks.

Sort of depends upon what you call trivial, I guess. This took me
about 10 minutes to write and debug (including comments). I guess I'd
still like to see it in Java (or even c++), just for fun.

(defvar *bindings* ())

;;; Match2 side effects *bindings* and then the match wrapper returns them.
;;; This makes passing them from one part of the tree to the next simpler,
;;; and also saves us from getting multiple copies on the output end.

(defun match (a b)
(setq *bindings* ())
(if (match2 a b) ;; The real work gets done by this subfn.
*bindings*))

(defun match2 (a b)
(cond ((var? a) ; if it's a var...
(if (bound? a) ; and it's already bound...
(match2 (bound? a) b) ; test that the binding holds.
(push (cons a b) *bindings*))) ; ... otherwise, bind it.
;; Check that we haven't hit bottom on either side.
((atom a) (eq a b))
((atom b) ()) ; if b hit bottom before a, luser!
;; And around we go...
(t (and (match2 (car a) (car b))
(match2 (cdr a) (cdr b))
))
)
))

(defun bound? (a)
(cdr (assoc a *bindings*)))

(defun var? (a)
(and (atom a)
(char-equal (aref (symbol-name a) 0) #\?)))

(defun test ()
(trace match)
(match '(a (?1 (?2 d)) ?2 ?1) '(a ((x y) ((c v) d)) (c v) (x y)))
(match '(a (?1 (?2 d)) ?2 ?1) '(a ((x y) ((c v) d)) (c v) (y x)))
(match '(a (?1 (?2 d)) ?2 ?1) '(a (test ((c v) d)) (c v) test))
(match '(a (?1 (?2 d)) ?2 ?1) '(a ((x y) ((c v) test)) (c v) (x y)))
(untrace)
)

>(test)
1> (MATCH (A (?1 (?2 D)) ?2 ?1) (A ((X Y) ((C V) D)) (C V) (X Y)))
<1 (MATCH ((?2 C V) (?1 X Y)))
1> (MATCH (A (?1 (?2 D)) ?2 ?1) (A ((X Y) ((C V) D)) (C V) (Y X)))
<1 (MATCH NIL)
1> (MATCH (A (?1 (?2 D)) ?2 ?1) (A (TEST ((C V) D)) (C V) TEST))
<1 (MATCH ((?2 C V) (?1 . TEST)))
1> (MATCH (A (?1 (?2 D)) ?2 ?1) (A ((X Y) ((C V) TEST)) (C V) (X Y)))
<1 (MATCH NIL)
(MATCH)

>

William Annis

unread,
Dec 20, 1996, 3:00:00 AM12/20/96
to

Jeff Shrager (shr...@neurocog.lrdc.pitt.edu) wrote:
: : Symbolic computation is NOT one of those lispy things Java

: : borrowed. Doing the matching above would take some work. Of course,
: : doing it in lisp is also non-trivial, which is why it figures nicely in so
: : many Lisp textbooks.

: Sort of depends upon what you call trivial, I guess. This took me
: about 10 minutes to write and debug (including comments). I guess I'd
: still like to see it in Java (or even c++), just for fun.

Well, it's certainly non-trivial in Java. As with C or C++,
we'd have to decide on some representation for your patterns. If I was
going to use the list notation, I'd proably just use one of the toy lisp
or scheme interpreters written in Java. :)

I'll think about the problem for a bit, and hopefully I'll have
time to code something up for comparison in the next week or so.

Will Fitzgerald

unread,
Dec 20, 1996, 3:00:00 AM12/20/96
to


Jeff Shrager <shr...@neurocog.lrdc.pitt.edu> wrote in article
<59cda1$8...@usenet.srv.cis.pitt.edu>...


> : Symbolic computation is NOT one of those lispy things Java
> : borrowed. Doing the matching above would take some work. Of course,
> : doing it in lisp is also non-trivial, which is why it figures nicely in
so
> : many Lisp textbooks.
>
> Sort of depends upon what you call trivial, I guess. This took me
> about 10 minutes to write and debug (including comments). I guess I'd
> still like to see it in Java (or even c++), just for fun.
>

One reason, I think, that it took you only about 10 minutes to write this
code is that it is such a classic Lisp example -- it's been solved in the
textbooks over and over again. That it will take more that 10 minutes to
do it in Java won't necessarily be a comment about Java, but about the lack
of prior solutions in Java. Of course, having done this many times in Lisp,
it should be easier to do in Java.

For example, the convention that variable names start with "?," and that
the way to test whether a symbol is a variable name is to look at the first
character of the symbol name is a relatively recent programming idiom in
Lisp, I believe. I remember when my Lisp guru -- Hi, Chris -- was
enlightened on this.

Perhaps a better way to write this matching function is to look through the
code examples found at the CMU AI Repository in the Lisp area:

<http://www.cs.cmu.edu/afs/cs.cmu.edu/project/ai-repository/ai/lang/lisp/0.h
tml>

in the code or bookcode directories. One might even learn something new!
(For example, how to write the matcher without using a global variable, how
to write easier to read accessor functions, etc.)

Jeff Shrager

unread,
Dec 20, 1996, 3:00:00 AM12/20/96
to

Well, although I take your point(s), I think that you've missed mine.
I wasn't trying to compare languages, at least not directly, nor to
learn anything new about lisp. Rather, I wanted to know whether Java
had incorporated convenient classical list procesing, which apparently
it hasn't, which I had (incorrectly) read into some previous postings
on it.

Thanks for the lisp programming advice, though. If you're looking for
a job, I'll send you a few tens of thousands of lines of code and you
can clean them up for me. :)

Cheers,
'Jeff

Dave Dyer

unread,
Dec 20, 1996, 3:00:00 AM12/20/96
to

> The main things that Java borrows from Lisp are:
>
> 1) Garbage collection.
> 2) Exception handling (via C++, probably).
> 3) The interfaces business is a bit like the
> "mixin" concept of Flavors. (In case you didn't
> read about these, when interfaces are "implemented"
> by a class definition you are expected to define
> certain methods. This avoids the stickiness of
> multiple inheritance but guarantees that
> certain functionality will exist for you.)
>

You forgot to mention:

Objects/Inheritance (single inheritance only)
inescapable Array bounds checking
inescapable type safety
absence of pointer arithmetic

and in java 1.1: bignums, introspection

---

Plus, java incorporates a bunch of modern language features
that lisp lacks, or doesn't fully support.

Encapsulated modules with defined interfaces, demand loading, and
compile-time and load-time verification of interfaces, inter-module security
etc. etc.

Method overloading

Serialization

And most important of all, Java has an *audience*. Hardly anybody cares about
lisp anymore. (Ouch, I can feel the flames already!).

--
My home page: http://www.andromeda.com/people/ddyer/home.html

Marty Hall

unread,
Dec 30, 1996, 3:00:00 AM12/30/96
to

shr...@neurocog.lrdc.pitt.edu (Jeff Shrager) writes:

[Marty returns from vacation to kick a week-dead horse]


> A number of folks here have said (w/o giving examples) that Java is
> somehow significantly closer to lisp than C++

I think "significantly closer" (perhaps even "closer") is an
exageration. However, having done 10 years of Lisp hacking, one year of
Java hacking, and intermittant C and C++ hacking, I see *some* ways in
which Java is closer to Lisp than to C++:

(A) Garbage collection.
(B) The way pointers are handled. No explicit
referencing/dereferencing; looks just like Lisp in this respect.
(C) Builtin hashing.
(D) How exceptions work.
(E) Runtime type information, and dynamic dispatch as the default.
(F) Higher-level libraries and general higher-level "feel".
(G) A parent class for all objects (Object).
(H) A language spec co-authored by Guy Steele. :-)

This is absolutely, positively, not intended to claim that Java has
all the good (or even a majority of the best) features of Lisp. In
addition to Jeff's symbolic processing example, features that many
Lisp programmers will miss include first-class functions (Java 1.1 has
a reasonable substitute), macros, multiple inheritance (Java
has a weak substitute), and prefix syntax. Some features that are
standard (and supposed to be portable) that Java has
that are missing or weak in Lisp *and* C++ include an easy to use
networking/sockets library, a threads library, a graphics library, and
a safety mechanism that allows a restricted class of Java programs
("applets") to be run safely on the client machine in Web browsers.

- Marty

Lisp Programming Resources: <http://www.apl.jhu.edu/~hall/lisp.html>
Java Programming Resources: <http://www.apl.jhu.edu/~hall/java/>

Howard R. Stearns

unread,
Dec 30, 1996, 3:00:00 AM12/30/96
to

Marty Hall wrote:
> ...

> I think "significantly closer" (perhaps even "closer") is an
> exageration. However, having done 10 years of Lisp hacking, one year of
> Java hacking, and intermittant C and C++ hacking, I see *some* ways in
> which Java is closer to Lisp than to C++:
> ...
> (D) How exceptions work.
> ...

Java, CL and C++ (sort of) all have exceptions, but, as I understand it,
there are some significant differences in how exception handling works.

For example, when Java throws an exception, the current frame is
searched for a handler. If none is found, the frame is (irrevocably)
popped off and the surrounding frame is searched.
- Although the searching for active handlers is by lexical scope, the
popping of frames is only by method, and not by some finer grained
scope.
- The notion of dynamic environment is somewhat weaker in Java than in
CL: there is no CATCH or dynamic variables. In any case, the
"dynamic environment" in which an exception handler executes in Java
is that of the method that contains the handler, not the one which
threw the exception.

Note that irrevocable nature of the popping of frames means that there
is no way for a handler to return control to an "inner" computation
(i.e. a restart).

(Maybe I'm missing something in my limited understanding of Java?)

By contrast, CL searches for a handler within the dynamic context of the
error. The handler is executed using its own lexical environment, but
the dynamic environment in which the error occured, except that none of
the handlers that were bound at the same time as the one invoked are
visible. By this measure, Java exceptions are somewhat like
HANDLER-CASE, but there is nothing comparable to HANDLER-BIND or
restarts.

Antonio Leitao

unread,
Dec 30, 1996, 3:00:00 AM12/30/96
to

>>>>> "Marty" =3D=3D Marty Hall <ha...@apl.jhu.edu> writes:

Marty> [...], features that many
Marty> Lisp programmers will miss include first-class functions (Java 1.1 =
has
Marty> a reasonable substitute), macros, multiple inheritance (Java
Marty> has a weak substitute) [...]

I would be very happy if you could elaborate a little longer on the
issues of first-class functions and multiple-inheritance in Java.

In what concerns first-class functions, I would like to know if you
are talking about something similar to the JGL Function Objects.

In what concerns multiple-inheritance, I would like to hear your
opinion about the usefullness of interfaces. As far as I can
understand interfaces, they only provide me with a new type which
allows the compiler to check correct method invocation. But the main
objective, which should be to provide mixins, is completely missed.

For example, in the awt package, I would like to add a kind of deamon
to TextFields, Buttons, RadioButtons, and so on. Each time the action
method is activated on one of those Components, the deamon is informed
of the fact. So, we want to redefine the action method of each of the
awt classes, and add some more methods that allow us to put a deamon on
a Component, to remove the deamon, etc.

With mixins and multiple-inheritance, this should be extremely
easy. With interfaces, I have to add a slot for the daemon to each
class of the awt, repeat the methods that add or remove the daemon,
and repeat the redefinition of the action method. The interface only
serves as a reminder of the methods that I must repeat on each awt
class.

What I object is that, in a good Object-Oriented language, I should
never *repeat* anything. If two or more classes need common behaviour,
they should inherit that behaviour from a common place, either from a
mixin (in multiple inheritance systems), or from some modification in
a parent class common to those classes (in single inheritance
systems). But with the awt, I can't (as far as I know) modify the
Component class, nor can I build interfaces with something else
besides abstract methods. As a conclusion, I must write the same
methods on each of the awt Component subclasses.

Finally, a last question. In many Object Oriented languages, I have a
first-class "dispatcher". What I mean by a first-class dispatcher is
something which can be used to call a method on an object without
knowing which method is it.

For example, in Flavors, I could write (send obj msg) and, depending
on the value of msg, some method of obj would be executed. In CLOS the
same behaviour is accomplished by funcall, using (funcall func obj),
where func evaluates to a generic function. In Smalltalk and
Objective-C there was a similar mechanism (I don't remember now what
was it).

My question is: can I do a similar thing in Java? How?
Please, don't tell me that I must use some standard type to encode the
"message" and then put a method on each object with a gigantic "if" that
dispatches "by hand" on the intended method.

Thanks in advance.

Ant=F3nio Leit=E3o.

Marty Hall

unread,
Dec 31, 1996, 3:00:00 AM12/31/96
to

Antonio Leitao <a...@gia.ist.utl.pt> writes:

>
> >>>>> Marty Hall <ha...@apl.jhu.edu> writes:
>
> Marty> [...], features that many Lisp
> Marty> programmers will miss include first-class functions (Java 1.1 has


> Marty> a reasonable substitute), macros, multiple inheritance (Java
> Marty> has a weak substitute) [...]
>
> I would be very happy if you could elaborate a little longer on the
> issues of first-class functions and multiple-inheritance in Java.
>
> In what concerns first-class functions, I would like to know if you
> are talking about something similar to the JGL Function Objects.

No, I am referring to two features of Java 1.1 (1.1 is in beta release
right now):
(A) Introspection, which basically gives you "funcall", albeit in
a way that seems a bit clumsy to the Lisper.
(B) Local classes, which basically gives you closures. Actually,
rather than passing functions that have access to the lexical
environment, you pass objects that have access to the lexical
environment, but the capabilities seem similar.

Even with this, Lisp's first class functions will be far more
convenient than Java's, plus of course Lisp has a rich infrastructure
of higher-order functions to work with these functions that you will
be passing around.

> In what concerns multiple-inheritance, I would like to hear your
> opinion about the usefullness of interfaces. As far as I can
> understand interfaces, they only provide me with a new type which
> allows the compiler to check correct method invocation. But the main
> objective, which should be to provide mixins, is completely missed.

I agree; Java's interfaces do NOT provide mixins. The way I often
explain interfaces is that they don't save the *author* of a particular
class any time, but are helpful to the *user* of a class. Interfaces
are nothing more than a promise that the class will implement certain
methods; you still have to completely rewrite those methods, even if
tons of classes use identical methods. So if class Foo is a subclass
of Bar and implements the Baz interface, Foo gets all the methods of
Foo, but has to directly implement all the methods of Bar.

However, users of Foo can treat it as either a Foo, Bar, *or* Baz, and
need not even know that Baz was an interface. This, for instance, lets
an author write a general sorting routine that can sort any array of
"Sortables", where all Sortables have a "compare" method that takes
two Sortables as input and returns true or false depending on whether
they are in the right order. Buttons, linked-lists, hash tables, or
other classes that already have a parent class could still be made
Sortables.

Having interfaces is better than single inheritance without
interfaces, but IMHO it is a huge exageration to say that Java
"almost" has multiple inheritance.

> Finally, a last question. In many Object Oriented languages, I have a
> first-class "dispatcher". What I mean by a first-class dispatcher is
> something which can be used to call a method on an object without
> knowing which method is it.
>
> For example, in Flavors, I could write (send obj msg) and, depending
> on the value of msg, some method of obj would be executed. In CLOS the
> same behaviour is accomplished by funcall, using (funcall func obj),
> where func evaluates to a generic function.

In Java 1.0-1.02, you would have tp have a Dispatcher class (or
interface) and make a new subclass for every kind of message you
wanted to send, then do msg1.send(obj), msg2.send(obj), etc.
Cumbersome and tedious.

Java 1.1 lets you do this more or less directly, however. Of course,
programs written in 1.1 won't run on 1.02 systems or browsers,
although 1.02 programs will (mostly) run in 1.1.

In summary, all three of these areas are ones in which Lisp has a
significant advantage, from my viewpoint. Macros is another big one.
Java, however, has some compensating advantages, depending on the
application.

Jeff Shrager

unread,
Dec 31, 1996, 3:00:00 AM12/31/96
to

I'm personally finding this interesting, and I hope that it continues
constructively (as opposed to turning into a brawl).

It would be very useful to me if folks who are both Java and Lisp
comptent would post some code comparisons. I tried to get someone to
do the matcher, but that seems too complex.

One thing that I've seen go by which is interesting is that Java has
done away with pointers (that is, they are invisible). Can someone
perhaps translate the following into Java? (I'll stick to numbers and
arrays so that we don't have to hassle about whether Java has symbols
(approx. atoms), which is seems not to have from what I've seen here
and in the tutorials I've read.)

Thanks,
'Jeff

;;; Create a tree of numical arrays where each node is an array containing
;;; either a number or another tree.

;;; Compose a complex nested tree that is just a few level deep.

(defun compose-random-array-tree (&optional (a (make-random-array)) (maxdepth 3))
(let ((length (first (array-dimensions a))))
(dotimes (address length)
(if (and (not (zerop maxdepth))
(zerop (random maxdepth)))
(setf (aref a address)
(compose-random-array-tree (make-random-array) (1- maxdepth)))
))
a))

;;; Create an array of random numbers at least three long.

(defun make-random-array ()
(let* ((length (+ 3 (random 10)))
(a (make-array length)))
(dotimes (address length)
(setf (aref a address) (random length)))
a))

;;; Reverse every array all the way down.

(defun reverse-array-tree (a &aux (length (first (array-dimensions a))))
;; First reverse all my children.
(dotimes (address length)
(let ((element (aref a address)))
(if (arrayp element)
(deep-reverse-array element))
))
;; Now reverse me. This is done the hard way, even though the
;; array is really just a sequence, because I doubt Java does sequences.
(dotimes (address (round (/ length 2.0)))
(let ((temp (aref a address)))
(setf (aref a address)
(aref a (- length address 1)))
(setf (aref a (- length address 1))
temp)))
)

;;; Example evaluation:

>(setq a (compose-random-array-tree))
#(0
#(0
#(#(2 6 2 4 0 3 0 7) #(11 4 1 0 4 11 4 8 5 8 7 7) #(1 1 0)
#(0 5 0 2 4 0) #(10 11 0 11 6 2 10 2 5 4 2 9)
#(0 2 5 4 9 8 4 1 4 5) #(6 7 2 1 8 4 4 2 7)
#(9 5 8 4 11 1 1 4 7 0 7 10) #(5 2 2 4 4 3 1 2 9 2 8) #(2 0 1))
1
#(#(3 2 0 11 10 7 7 9 9 5 10 2) #(1 3 3 1 1 0)
#(3 5 2 11 1 11 8 3 7 7 11 10) #(1 0 2) #(4 1 5 0 0 5) #(0 0 0)
#(3 4 3 1 1 2 7 4))
#(#(6 5 0 2 6 2 4) #(1 6 1 6 8 7 5 1 1) #(2 1 5 4 2 8 7 7 5)
#(3 5 1 2 5 3) #(4 0 3 2 3) #(1 6 4 9 2 5 7 2 2 3)
#(4 1 2 9 3 7 5 3 5 5) #(0 3 4 3 1) #(1 1 4 1 4 3 1)
#(1 0 4 2 1 0))
#(#(2 2 0 2 0) #(0 0 0) #(0 1 1) #(4 0 3 2 2 3 3 0)))
#(#(#(2 1 1) #(1 1 2 0) #(1 1 1) #(3 2 6 3 2 2 0) #(7 6 0 7 0 4 5 4)
#(7 0 9 0 11 3 2 4 3 0 10 8) #(1 6 5 3 4 0 4) #(2 2 4 3 3))
6 #(#(2 1 0) #(0 6 9 1 2 7 3 5 6 8 4 4) #(5 1 10 6 1 8 5 9 8 8 3))
5
#(#(2 6 0 0 0 7 4 1 1 10 6) #(4 2 4 1 1 2) #(0 0 0 0)
#(9 3 4 2 10 4 1 7 6 4 7) #(2 3 2 3 0 2 6 1 0 8) #(1 2 3 4 0 1 0)
#(1 1 0 5 10 3 1 0 11 3 10 11))
#(#(3 4 3 4 2) #(1 1 4 3 5 2) #(2 2 4 4 3) #(0 8 3 8 3 0 8 9 8 0)
#(8 5 4 7 6 0 9 2 2 3))
4 1 8 8))

>(reverse-array-tree a)
NIL

>a
#(#(8 8 1 4
#(#(3 2 2 9 0 6 7 4 5 8) #(0 8 9 8 0 3 8 3 8 0) #(3 4 4 2 2)
#(2 5 3 4 1 1) #(2 4 3 4 3))
#(#(11 10 3 11 0 1 3 10 5 0 1 1) #(0 1 0 4 3 2 1)
#(8 0 1 6 2 0 3 2 3 2) #(7 4 6 7 1 4 10 2 4 3 9) #(0 0 0 0)
#(2 1 1 4 2 4) #(6 10 1 1 4 7 0 0 0 6 2))
5 #(#(3 8 8 9 5 8 1 6 10 1 5) #(4 4 8 6 5 3 7 2 1 9 6 0) #(0 1 2))
6
#(#(3 3 4 2 2) #(4 0 4 3 5 6 1) #(8 10 0 3 4 2 3 11 0 9 0 7)
#(4 5 4 0 7 0 6 7) #(0 2 2 3 6 2 3) #(1 1 1) #(0 2 1 1) #(1 1 2)))
#(#(#(0 3 3 2 2 3 0 4) #(1 1 0) #(0 0 0) #(0 2 0 2 2))
#(#(0 1 2 4 0 1) #(1 3 4 1 4 1 1) #(1 3 4 3 0)
#(5 5 3 5 7 3 9 2 1 4) #(3 2 2 7 5 2 9 4 6 1) #(3 2 3 0 4)
#(3 5 2 1 5 3) #(5 7 7 8 2 4 5 1 2) #(1 1 5 7 8 6 1 6 1)
#(4 2 6 2 0 5 6))
#(#(4 7 2 1 1 3 4 3) #(0 0 0) #(5 0 0 5 1 4) #(2 0 1)
#(10 11 7 7 3 8 11 1 11 2 5 3) #(0 1 1 3 3 1)
#(2 10 5 9 9 7 7 10 11 0 2 3))
1
#(#(1 0 2) #(8 2 9 2 1 3 4 4 2 2 5) #(10 7 0 7 4 1 1 11 4 8 5 9)
#(7 2 4 4 8 1 2 7 6) #(5 4 1 4 8 9 4 5 2 0)
#(9 2 4 5 2 10 2 6 11 0 11 10) #(0 4 2 0 5 0) #(0 1 1)
#(7 7 8 5 8 4 11 4 0 1 4 11) #(7 0 3 0 4 2 6 2))
0)
0)


Dave Dyer

unread,
Dec 31, 1996, 3:00:00 AM12/31/96
to

>;;; Create a tree of numical arrays where each node is an array containing
>;;; either a number or another tree.
>

You've picked at another of Java's warts; that there is a harsh
line between numbers, characters and other fundamnental types -
and objects. You cannot create an array which contains either
a number or another array. Instead, you would have to use the
container class Integer or some equivalent. Not exactly elegant;
but there is good motivation for this in Java's design. Java never
has to box numbers.

public class array_tree
{
/** construct a random array consisting of small integers and arrays */
static Object [] make_random_array(int max_depth, int max_length,int min_length)
{ int length = (int)(Math.random()*(max_length-min_length))+min_length;
Object result[] = new Object[length];
for(int address=0;address<length;address++)
{ result[address]= ((Math.random()*max_depth)>=1.0)
?
(Object)(make_random_array(max_depth-1,max_length,min_length))
: (Object)(new Integer((int)(Math.random()*length)));
}
return(result);
}
/** make random array with default length profile of 3-10 */
static Object [] make_random_array(int max_depth)
{ return(make_random_array(max_depth,10,3));
}
static void reverse_array_tree(Object []a)
{
for(int i=0;i<a.length;i++)
{/* note that the instanceof and the cast are both required. It would
not work
to define an additional dummy method, reverse_array_tree(Object a) {},
and write just reverse_array_tree(a[i]) ,
because Java dispatches based on the compile-time type
*/
if(a[i] instanceof Object[]) { reverse_array_tree((Object [])a[i]); }
}
for(int i=0,j=a.length-1; i<j; i++,j--)
{ Object temp = a[i];
a[i]=a[j];
a[j]=temp;
}
}

/** to complete the example in Java, we have to define our own pretty-print */
static void print_array_tree(Object a[],int level)
{ System.out.println();
for(int i=0;i<level;i++) { System.out.print(" "); }
System.out.print("(");
for(int i=0;i<a.length;i++)
{if(a[i] instanceof Object[])
{ print_array_tree((Object [])a[i],level+1);
}
else
{ System.out.print(a[i] + " ");
}
}
System.out.println(")");
for(int i=0;i<level;i++) { System.out.print(" "); }
}
public static void main(String args[])
{ Object ar[]=make_random_array(3,5,3);
print_array_tree(ar,0);
reverse_array_tree(ar);
print_array_tree(ar,0);
}
}

sample output:

(
(1 0
(1 1 0 )
)

(
(0 2 0 )

(2 2 0 )
1 )
1 )

(1
(1
(0 2 2 )

(0 2 0 )
)

(
(0 1 1 )
0 1 )
)

Jeffrey Mark Siskind

unread,
Jan 3, 1997, 3:00:00 AM1/3/97
to

In article <ddyer-31129...@192.0.2.1> dd...@netcom.com (Dave Dyer) writes:

You've picked at another of Java's warts; that there is a harsh
line between numbers, characters and other fundamnental types -
and objects. You cannot create an array which contains either
a number or another array. Instead, you would have to use the
container class Integer or some equivalent. Not exactly elegant;
but there is good motivation for this in Java's design. Java never
has to box numbers.

Boxing is an implementation issue, not a language-design issue. Scheme allows
arrays to contain scalar type or other arrays (or even heterogeneous mixtures
of scalar types and other arrays). And the Stalin compiler for Scheme never
boxes numbers (or any immutable fixed-length type for that matter).
--

Jeff (home page http://www.emba.uvm.edu/~qobi)

Dave Dyer

unread,
Jan 3, 1997, 3:00:00 AM1/3/97
to

>
>Boxing is an implementation issue, not a language-design issue. Scheme allows
>arrays to contain scalar type or other arrays (or even heterogeneous mixtures
>of scalar types and other arrays). And the Stalin compiler for Scheme never
>boxes numbers (or any immutable fixed-length type for that matter).
>--

There's no free lunch. Either you always use more than N bits to
represent an N bit integer, or you sometimes have to build boxes.
Either you know the type at compile time or you sometimes have to
check.

Java always uses 32 bits for integers, and always knows (absolutely,
unambigously) if a quantity it is manipulating is an integer. This
maximizes both storage and computational effeciency - at the cost of
introducing ugly workarounds in the relatively rare cases where mixed
types are needed.

Jeff Shrager

unread,
Jan 5, 1997, 3:00:00 AM1/5/97
to

Thanks *very* much for taking the time to write this. I'm curious
about your remark that:

: [...] there is a harsh


: line between numbers, characters and other fundamnental types -

: and objects. You cannot create an array which contains either
: a number or another array. Instead, you would have to use the


: container class Integer or some equivalent. Not exactly elegant;
: but there is good motivation for this in Java's design.

And your implementation of the array as an Object:

: static Object [] make_random_array(int max_depth,
: int max_length, int min_length)


: { int length = (int)(Math.random()*(max_length-min_length))+min_length;
: Object result[] = new Object[length];

: ...

This doesn't seem horrible; we use lists, Javists use object arrays,
but I wonder about the extensibility of such an array. Can you
arbitrarily add elements to one of these things, they way you can with
a list? Apparently there's no builing thing like a list, but I assume
that it'd be simple to implement one or they'd have built it it.

For example, consider the simple (destructive) nconc:

(defun nconc (l1 l2)
(rplacd (last l1) l2)
l1) ; this can be left off if all you care about is the side-effect

Ignoring the fact that this is a lisp built-in; and using whatever
would be the most natural representation for a list in Java, what's
the Java equivalent?, or do you need to first import or design a list
type to do the work on? (Again, code would be great!)

Thanks,
Cheers,
'Jeff

Marty Hall

unread,
Jan 6, 1997, 3:00:00 AM1/6/97
to

shr...@neurocog.lrdc.pitt.edu (Jeff Shrager) writes:

> This doesn't seem horrible; we use lists, Javists use object arrays,
> but I wonder about the extensibility of such an array. Can you
> arbitrarily add elements to one of these things, they way you can with
> a list?

Java has what it calls Vectors: stretchy arrays that let you insert or
remove elements from the front, middle (overwriting or splicing), or
back. Insertions at the front or middle cause everything to be
shuffled down, however, so there is no O(1) insert or splice as in
Lisp. However, the underlying implementation is an array that gets
doubled every time it gets full (like hash tables in Lisp and
Java). So the amortized costs of N appends on a Vector in Java is
O(N), since the number of copies into new arrays is at most N/2 + N/4
+ ... + 1, which is N-1. This is nice, but of course, no Lisp
programmer would do N appends by simply doing (setq List (append List
New-Element)), since we all know that is O(N^2).

The API for Vectors is available at
http://www.javasoft.com/JDK-1.0/api/java.util.Vector.html.

With Java Vectors, like any heterogeneous collection in Java, you have
to cast the element to the proper type after yanking it out of the
Vector, even if you know ahead of time that it is a Vector entirely of
Foos. You can define a subclass that does this, but without
parameterized types, this can be a bit tedious.

> Apparently there's no builtin thing like a list, but I assume


> that it'd be simple to implement one or they'd have built it it.

It is quite simple to implement. Very similar to what you would do in
Lisp if you had DEFSTRUCT but not lists.

Marco Antoniotti

unread,
Jan 7, 1997, 3:00:00 AM1/7/97
to

shr...@neurocog.lrdc.pitt.edu (Jeff Shrager) writes:

>
> Thanks *very* much for taking the time to write this. I'm curious
> about your remark that:
>
> : ...
>

> This doesn't seem horrible; we use lists, Javists use object arrays,
> but I wonder about the extensibility of such an array. Can you
> arbitrarily add elements to one of these things, they way you can with

> a list? Apparently there's no builing thing like a list, but I assume


> that it'd be simple to implement one or they'd have built it it.

> 'Jeff

Java has a class called Vector which implements 'extensible' arrays.
I do not have the manual (or the web page) at hand, but it seems that
'Vectors' are what you ask for (even though they are more similar to
Common Lisp arrays.)

Cheers


--
Marco Antoniotti - Resistente Umano
===============================================================================
...it is simplicity that is difficult to make.
...e` la semplicita` che e` difficile a farsi.
Bertholdt Brecht

Tim Bradshaw

unread,
Jan 7, 1997, 3:00:00 AM1/7/97
to

* Dave Dyer wrote:
>> ;;; Create a tree of numical arrays where each node is an array containing
>> ;;; either a number or another tree.
>>
> You've picked at another of Java's warts; that there is a harsh

> line between numbers, characters and other fundamnental types -
> and objects. You cannot create an array which contains either
> a number or another array. Instead, you would have to use the
> container class Integer or some equivalent. Not exactly elegant;
> but there is good motivation for this in Java's design. Java never
> has to box numbers.

One could equally well phrase this as `Java relies on the user to box
numbers for it -- by putting them in a container class by steam'!

It's always seemed to me that this (making numbers not be objects and
then having the user box them by hand) is kind of a cop-out solution.
If you have a properly-done type system then you should be able to do
enough type inference that you only have to box numbers when you
actually do need to box them, and that things can then be boxed by the
system without you having to worry about it.

OTOH I've never actually used a language which can actually do this
well enough to be really usable -- CMUCL's compiler gets close
sometimes, but I suspect it's crippled by CL's type system. Do
languages (or implementations) which can do this, and which have
object systems (or at least an extensible type hierarchy) exist?

--tim

Marco Antoniotti

unread,
Jan 9, 1997, 3:00:00 AM1/9/97
to

Tim Bradshaw <t...@aiai.ed.ac.uk> writes:

>
...


>
> OTOH I've never actually used a language which can actually do this
> well enough to be really usable -- CMUCL's compiler gets close
> sometimes, but I suspect it's crippled by CL's type system. Do
> languages (or implementations) which can do this, and which have
> object systems (or at least an extensible type hierarchy) exist?

Supposedly Dylan has this as one of its design goals. The CMU folks
must have rolled back quite a bit of Python in their system

--
Marco Antoniotti - Resistente Umano
===============================================================================

International Computer Science Institute | mar...@icsi.berkeley.edu
1947 Center STR, Suite 600 | tel. +1 (510) 643 9153
Berkeley, CA, 94704-1198, USA | +1 (510) 642 4274 x149

Dave Dyer

unread,
Jan 11, 1997, 3:00:00 AM1/11/97
to

>It's always seemed to me that this (making numbers not be objects and
>then having the user box them by hand) is kind of a cop-out solution.
>If you have a properly-done type system then you should be able to do
>enough type inference that you only have to box numbers when you
>actually do need to box them, and that things can then be boxed by the
>system without you having to worry about it.
>

>OTOH I've never actually used a language which can actually do this
>well enough to be really usable -- CMUCL's compiler gets close
>sometimes, but I suspect it's crippled by CL's type system. Do
>languages (or implementations) which can do this, and which have
>object systems (or at least an extensible type hierarchy) exist?
>

In Java, numbers only have to be boxed when you insist that the same
container be able to contain either a number or a non-number. It's
actually not too bad except in one common case; that you'd like a function
to return either a number or something like "null".

I think the strongest reason why Java adopted this strategy is not
to save the complexity of figuring out when to make boxes, but to
reduce complexity in memory management and garbage collection.

0 new messages