Clojure presentation

175 views
Skip to first unread message

Rich Hickey

unread,
Dec 3, 2007, 9:23:57 PM12/3/07
to Clojure
I recently gave a talk on Clojure to the LispNYC group. Audio and
slides from the talk are now available online:

http://lispnyc.org/wiki.clp?page=past-meetings

John Cowan

unread,
Dec 4, 2007, 7:08:13 PM12/4/07
to clo...@googlegroups.com
On Dec 3, 2007 9:23 PM, Rich Hickey <richh...@gmail.com> wrote:

> I recently gave a talk on Clojure to the LispNYC group. Audio and
> slides from the talk are now available online:

Since you say in your presentation slides that Clojure is still alpha,
I wonder if there's any chance that you would change some of the
names of standard functions and special forms? It's clear that
Clojure is now more Schemish than CLish, even though it
began life as a CL implementation before going in the
new direction that you describe (which I admire greatly).
That being so, it would make life easier for Scheme programmers
if Scheme names were used when they make sense:
#t instead of :t and discriminating between #f and nil,
equal? instead of eql? (which suggests CL's EQL, which it
is not), named-let rather than loop and recur, etc.

If this pushes your buttons, disregard it.

--
GMail doesn't have rotating .sigs, but you can see mine at
http://www.ccil.org/~cowan/signatures

Rich Hickey

unread,
Dec 5, 2007, 10:54:50 AM12/5/07
to Clojure


On Dec 4, 7:08 pm, "John Cowan" <johnwco...@gmail.com> wrote:
> On Dec 3, 2007 9:23 PM, Rich Hickey <richhic...@gmail.com> wrote:
>
> > I recently gave a talk on Clojure to the LispNYC group. Audio and
> > slides from the talk are now available online:
>
> Since you say in your presentation slides that Clojure is still alpha,
> I wonder if there's any chance that you would change some of the
> names of standard functions and special forms? It's clear that
> Clojure is now more Schemish than CLish, even though it
> began life as a CL implementation before going in the
> new direction that you describe (which I admire greatly).
> That being so, it would make life easier for Scheme programmers
> if Scheme names were used when they make sense:
> #t instead of :t and discriminating between #f and nil,
> equal? instead of eql? (which suggests CL's EQL, which it
> is not), named-let rather than loop and recur, etc.
>
> If this pushes your buttons, disregard it.

Just don't call my baby ugly! :)

No buttons pushed, but issues worth addressing.

Yes, one of the reasons Clojure is alpha is that some names might
change. One of the side effects of abandoning backwards compatibility
is the possibility of annoying/offending/confusing just about everyone
who might have sufficient experience in another language to enable
them to 'get' Clojure relatively quickly. That's one of the reasons
for the Lisp-differences page, but I've gotten exhausted trying to
maintain it - there are so many (small) differences! I think I'll need
to offer more general advice to please bring in one's understanding of
fundamentals but check one's presumptions of specifics.

I have taken some care about names in general. Not that they are all
great, but they are considered. One of the danger zones are names
already used by older languages. If the meaning is just slightly
different (let binding sequentially), I think it can be more of a
problem than reusing a name for completely different purposes (do,
assoc). OTOH, one can't let older languages 'own' words - there are
only so many good short ones!

To your suggestions:

I'm trying to reserve leading # for reader macros.

recur is in Clojure for a very specific reason - it, and only it, is
guaranteed to turn into a non-stack-consuming loop. In the absence of
a full TCO promise, and any other looping construct, it is essential
people know when they are going to get a loop. named-let is not the
same - a call to the named function can appear in a non-tail position,
and the function object can be passed/returned. Not that I am against
adding named-let/letrec, they may still appear, as I am not totally
happy with thisfn.

Clojure may be like Scheme in it's Lisp-1 nature, but it is more like
CL in its treatment of nil and conditionals. I prefer conditionals to
test for nil rather than false. If everything is conditional true,
than 'nothing' should be conditional false (CL, Clojure). If there is
a distinguished value for false, there should be a corresponding
distinguished value for true (Java). Scheme tries to have it both
ways. One could argue that it's just a naming thing - I could have
called nil #f and it would be the same as Scheme. But Clojure is a
hosted language and the host platform distinguishes null and false,
and I have equated Clojure nil and Java null. In Clojure, nil means
'nothing/no object', and conditionals test for something/nothing.

Empty collections are not nothing (so they are conditional true, like
Scheme!), nor are they all the same thing (so, no Scheme null?, but
could have empty?). Clojure seqs are logical streams and when they are
consumed you are left with nothing, not an empty collection, so rest
returns nil. I think it is extremely useful for rest to return
conditional false (like CL). It leads to succinct and elegant idioms.

I guess the short answer is there's no 'false' because that is not how
Clojure works, and Clojure works differently than both CL and Scheme.

eql? is not great. You're right, CLers might expect eql, and as far as
Clojure and its data structures, eql? is mostly the same as Scheme
equal? (although one could argue that the ability of equal? to return
true for mutable objects in Scheme is an error - see
http://home.pipeline.com/~hbaker1/ObjectIdentity.html). Unfortunately,
I can't guarantee any semantics fully, because the real mapping is to
Java's Object.equals(), which lets each class determine its own
meaning. Clojure data structures define equals like Scheme equal? (or
Baker's egal), but many Java classes do not (hmmm... actually many do
follow egal in defaulting to mutability and reference equality). I
guess the name should be 'equals', but I'd really like something much
shorter. I wanted to use ==, but am afraid that Java programmers will
expect a reference comparison. egal seemed too weird. Open to
suggestions (but suggesters should read Baker's paper first, please).

Rich

Henk Boom

unread,
Dec 5, 2007, 1:04:51 PM12/5/07
to clo...@googlegroups.com
On 05/12/2007, Rich Hickey <richh...@gmail.com> wrote:

> Not that I am against
> adding named-let/letrec, they may still appear, as I am not totally
> happy with thisfn.

Indeed. Don't you loose thisfn's use for a function the moment you
ender any nested function definitions? Also, mutual recursion can be
useful even without TCO (as long as you're careful).

What about adding a parallel let? There are some times it's useful,
and it's a hint to the reader that the definitions need not be
sequential.

> Clojure may be like Scheme in it's Lisp-1 nature, but it is more like
> CL in its treatment of nil and conditionals. I prefer conditionals to
> test for nil rather than false. If everything is conditional true,
> than 'nothing' should be conditional false (CL, Clojure). If there is
> a distinguished value for false, there should be a corresponding
> distinguished value for true (Java). Scheme tries to have it both
> ways. One could argue that it's just a naming thing - I could have
> called nil #f and it would be the same as Scheme. But Clojure is a
> hosted language and the host platform distinguishes null and false,
> and I have equated Clojure nil and Java null. In Clojure, nil means
> 'nothing/no object', and conditionals test for something/nothing.
>
> Empty collections are not nothing (so they are conditional true, like
> Scheme!), nor are they all the same thing (so, no Scheme null?, but
> could have empty?). Clojure seqs are logical streams and when they are
> consumed you are left with nothing, not an empty collection, so rest
> returns nil. I think it is extremely useful for rest to return
> conditional false (like CL). It leads to succinct and elegant idioms.

I agree that it makes some kind of sense for (rest '(1)) to return nil
(though I find (if (empty? s) a b) clearer than (if s b a)). What
about (first '()), (rest '()), (first nil), and (rest nil) though? I
those be contract violations. Otherwise it feels almost like every seq
has an infinite number of nils on the end =).

Also, currently I don't see an easy way of telling when a key is
mapped to nil in hash-tables. In PLT-Scheme the hash-table lookup
function takes an optional argument which is the value to return when
the key is not found. Should this be implemented?

(Also^2, if maps are seqs, I would expect to be able (key (first m))
and (value (first m)) to extract information from them. 'values' and
keys' don't seem really useful to me once that works. Currently it
seems that (first m) and (rest m) do not produce useful results.)

> eql? is not great. You're right, CLers might expect eql, and as far as
> Clojure and its data structures, eql? is mostly the same as Scheme
> equal? (although one could argue that the ability of equal? to return
> true for mutable objects in Scheme is an error - see
> http://home.pipeline.com/~hbaker1/ObjectIdentity.html). Unfortunately,
> I can't guarantee any semantics fully, because the real mapping is to
> Java's Object.equals(), which lets each class determine its own
> meaning. Clojure data structures define equals like Scheme equal? (or
> Baker's egal), but many Java classes do not (hmmm... actually many do
> follow egal in defaulting to mutability and reference equality). I
> guess the name should be 'equals', but I'd really like something much
> shorter. I wanted to use ==, but am afraid that Java programmers will
> expect a reference comparison. egal seemed too weird. Open to
> suggestions (but suggesters should read Baker's paper first, please).

Definitely have suggestions, but I'll read the paper first. Is the
java '==' exposed in clojure? '==' itself seems only to work on
numbers (of course this is incompatible, given that clojure use
by-reference numbers). Maybe the current '==' should be '=?' and a new
'==?' should expose the Java '=='?

On a slightly different note, looking at the comparators in boot.clj,
they don't seem to use recur. (apply == (repeat 1)) gives a stack
overflow instead of an endless loop. Of course, I doubt anyone would
ever want to do this, but they might want to apply == to arbitrarily
long seqs.

Henk Boom

Rich Hickey

unread,
Dec 5, 2007, 2:45:23 PM12/5/07
to Clojure


On Dec 5, 1:04 pm, "Henk Boom" <lunarcri...@gmail.com> wrote:
> On 05/12/2007, Rich Hickey <richhic...@gmail.com> wrote:
>
> > Not that I am against
> > adding named-let/letrec, they may still appear, as I am not totally
> > happy with thisfn.
>
> Indeed. Don't you loose thisfn's use for a function the moment you
> ender any nested function definitions?

Yes, although you could bind it with let if you still needed access.
The problem is macros that expand to nested fns.

> Also, mutual recursion can be
> useful even without TCO (as long as you're careful).
>

Agreed. Note that mutual recursion is possible with top-level
functions, just not nested ones (yet).

> What about adding a parallel let? There are some times it's useful,
> and it's a hint to the reader that the definitions need not be
> sequential.
>

I'm not convinced of its utility - got a good example?

>
> > Clojure may be like Scheme in it's Lisp-1 nature, but it is more like
> > CL in its treatment of nil and conditionals. I prefer conditionals to
> > test for nil rather than false. If everything is conditional true,
> > than 'nothing' should be conditional false (CL, Clojure). If there is
> > a distinguished value for false, there should be a corresponding
> > distinguished value for true (Java). Scheme tries to have it both
> > ways. One could argue that it's just a naming thing - I could have
> > called nil #f and it would be the same as Scheme. But Clojure is a
> > hosted language and the host platform distinguishes null and false,
> > and I have equated Clojure nil and Java null. In Clojure, nil means
> > 'nothing/no object', and conditionals test for something/nothing.
>
> > Empty collections are not nothing (so they are conditional true, like
> > Scheme!), nor are they all the same thing (so, no Scheme null?, but
> > could have empty?). Clojure seqs are logical streams and when they are
> > consumed you are left with nothing, not an empty collection, so rest
> > returns nil. I think it is extremely useful for rest to return
> > conditional false (like CL). It leads to succinct and elegant idioms.
>
> I agree that it makes some kind of sense for (rest '(1)) to return nil
> (though I find (if (empty? s) a b) clearer than (if s b a)). What
> about (first '()), (rest '()), (first nil), and (rest nil) though? I
> those be contract violations. Otherwise it feels almost like every seq
> has an infinite number of nils on the end =).
>

It's not a contract violation unless I promised otherwise :) That's
the way it is in Common Lisp and I find it very practical. Whether it
feels 'wrong' is mostly a matter of perspective.

> Also, currently I don't see an easy way of telling when a key is
> mapped to nil in hash-tables. In PLT-Scheme the hash-table lookup
> function takes an optional argument which is the value to return when
> the key is not found. Should this be implemented?
>

Already on the todo list. Right now you can use contains if you are
putting nils into maps.

> (Also^2, if maps are seqs, I would expect to be able (key (first m))
> and (value (first m)) to extract information from them.

Also already on the todo list. Right now I am using my own IMapEntry
but I am going to switch to implementing Map.Entry, and will provide
key and val functions. Until then you can do this:

(. (first m) (key)) and (. (first m) (val))

> 'values' and
> keys' don't seem really useful to me once that works.

Fair enough, but I think I'll keep them.

> > eql? is not great. You're right, CLers might expect eql, and as far as
> > Clojure and its data structures, eql? is mostly the same as Scheme
> > equal? (although one could argue that the ability of equal? to return
> > true for mutable objects in Scheme is an error - see
> >http://home.pipeline.com/~hbaker1/ObjectIdentity.html). Unfortunately,
> > I can't guarantee any semantics fully, because the real mapping is to
> > Java's Object.equals(), which lets each class determine its own
> > meaning. Clojure data structures define equals like Scheme equal? (or
> > Baker's egal), but many Java classes do not (hmmm... actually many do
> > follow egal in defaulting to mutability and reference equality). I
> > guess the name should be 'equals', but I'd really like something much
> > shorter. I wanted to use ==, but am afraid that Java programmers will
> > expect a reference comparison. egal seemed too weird. Open to
> > suggestions (but suggesters should read Baker's paper first, please).
>
> Definitely have suggestions, but I'll read the paper first. Is the
> java '==' exposed in clojure? '==' itself seems only to work on
> numbers (of course this is incompatible, given that clojure use
> by-reference numbers).

Clojure may box numbers but it always treats them as values. ==
currently behaves the way == behaves in Java _for numbers_, i.e. == in
Java compares numbers by value and references by identity. Reference
identity comparison is not yet implemented in Clojure.

> Maybe the current '==' should be '=?' and a new
> '==?' should expose the Java '=='?
>
I don't like Java's ==, will probably provide a separate identical?
function and limit == to numbers.

=? is interesting as the core equality predicate.

> On a slightly different note, looking at the comparators in boot.clj,
> they don't seem to use recur. (apply == (repeat 1)) gives a stack
> overflow instead of an endless loop. Of course, I doubt anyone would
> ever want to do this, but they might want to apply == to arbitrarily
> long seqs.
>

I agree, will fix.

Rich

Henk Boom

unread,
Dec 5, 2007, 3:28:31 PM12/5/07
to clo...@googlegroups.com
On 05/12/2007, Rich Hickey <richh...@gmail.com> wrote:
> > What about adding a parallel let? There are some times it's useful,
> > and it's a hint to the reader that the definitions need not be
> > sequential.
> >
>
> I'm not convinced of its utility - got a good example?
>

Well, the main practical difference is when the variables you are
binding share names with old ones, so any example I could give of
parallel let usage could be made into a sequential let usage by
prepending all the names with 'new-' or similar.

The real reason I like parallel let is that it's symmetrical in that
all the values are evaluated in the same scope. I find this makes code
more understandable as you don't have to be worrying what effect the
early bindings in the let have on the later ones. It's a signal to the
reader as to what the value is based on.

> > What
> > about (first '()), (rest '()), (first nil), and (rest nil) though? I
> > those be contract violations. Otherwise it feels almost like every seq
> > has an infinite number of nils on the end =).
> >
>
> It's not a contract violation unless I promised otherwise :) That's
> the way it is in Common Lisp and I find it very practical. Whether it
> feels 'wrong' is mostly a matter of perspective.

Do you have an example of where it is useful to use first or rest on
nil? To me it feels like taking the car or cdr of the empty list (in
scheme this is a contract violation).

> > <feature request>


>
> Already on the todo list. Right now you can use contains if you are
> putting nils into maps.
>

> > <feature request>


>
> Also already on the todo list. Right now I am using my own IMapEntry
> but I am going to switch to implementing Map.Entry, and will provide
> key and val functions. Until then you can do this:

Cool!

> > Maybe the current '==' should be '=?' and a new
> > '==?' should expose the Java '=='?
> >
> I don't like Java's ==, will probably provide a separate identical?
> function and limit == to numbers.

Why no '?' if it is solely a predicate?

>
> =? is interesting as the core equality predicate.
>

Is this where egal goes? I thought eql? was going to be used this way
(as far as it can given some java classes' implementations of
equals()).

Henk Boom

Rich Hickey

unread,
Dec 5, 2007, 4:38:37 PM12/5/07
to Clojure


On Dec 5, 3:28 pm, "Henk Boom" <lunarcri...@gmail.com> wrote:
> On 05/12/2007, Rich Hickey <richhic...@gmail.com> wrote:
>
> > > What about adding a parallel let? There are some times it's useful,
> > > and it's a hint to the reader that the definitions need not be
> > > sequential.
>
> > I'm not convinced of its utility - got a good example?
>
> Well, the main practical difference is when the variables you are
> binding share names with old ones, so any example I could give of
> parallel let usage could be made into a sequential let usage by
> prepending all the names with 'new-' or similar.
>

And probably should be renamed.

> The real reason I like parallel let is that it's symmetrical in that
> all the values are evaluated in the same scope. I find this makes code
> more understandable as you don't have to be worrying what effect the
> early bindings in the let have on the later ones. It's a signal to the
> reader as to what the value is based on.
>

I think this is more a matter of expectations. In SML let binds
sequentially and I don't think anyone is worried by that. Hopefully
let binding lists are not too long. In any case, understanding the
meaning of an initializer means examining the enclosing scope - it now
just includes the preceding bindings.

> > > What
> > > about (first '()), (rest '()), (first nil), and (rest nil) though? I
> > > those be contract violations. Otherwise it feels almost like every seq
> > > has an infinite number of nils on the end =).
>
> > It's not a contract violation unless I promised otherwise :) That's
> > the way it is in Common Lisp and I find it very practical. Whether it
> > feels 'wrong' is mostly a matter of perspective.
>
> Do you have an example of where it is useful to use first or rest on
> nil? To me it feels like taking the car or cdr of the empty list (in
> scheme this is a contract violation).
>

This is a very old argument. There is no right or wrong. I'm with
Common Lisp here, and so is Clojure, but this hints at the
practicality issue in a fun way:

http://people.cs.uchicago.edu/~wiseman/humor/large-programs.html

In any case, if one wants functions that behave like first and rest
but throw exceptions when passed nil, it is easy to define them in
terms of the first and rest provided, but the converse is not true.

> > > Maybe the current '==' should be '=?' and a new
> > > '==?' should expose the Java '=='?
>
> > I don't like Java's ==, will probably provide a separate identical?
> > function and limit == to numbers.
>
> Why no '?' if it is solely a predicate?
>

== is a nice operator and people will expect it to do something, so it
does what Java's does, for numbers only. Like Scheme's = has no "?"

> > =? is interesting as the core equality predicate.
>
> Is this where egal goes? I thought eql? was going to be used this way
> (as far as it can given some java classes' implementations of
> equals()).

Yes, =? would replace eql?. The complaint of the original poster on
this topic was eql?'s similarity to CL eql, while behaving much
differently.

Rich

John Cowan

unread,
Dec 5, 2007, 5:56:08 PM12/5/07
to clo...@googlegroups.com
On Dec 5, 2007 10:54 AM, Rich Hickey <richh...@gmail.com> wrote:
> recur is in Clojure for a very specific reason - it, and only it, is
> guaranteed to turn into a non-stack-consuming loop. In the absence of
> a full TCO promise, and any other looping construct, it is essential
> people know when they are going to get a loop. named-let is not the
> same - a call to the named function can appear in a non-tail position,
> and the function object can be passed/returned.

I don't consider those huge problems, especially not allowing the
function to escape. However, it would be useful to be able to
recur an outer loop from within an inner loop, which named let
would allow (or does that not work for implementation reasons)?

> Clojure is a
> hosted language and the host platform distinguishes null and false,
> and I have equated Clojure nil and Java null. In Clojure, nil means
> 'nothing/no object', and conditionals test for something/nothing.

So when you call a Java method from Clojure code, you map nil
to false if the argument is boolean, and to null if it's an object?
(Theoretically there would be a problem if the argument is
java.lang.Boolean, I guess, since null would be valid.)

> Empty collections are not nothing (so they are conditional true, like
> Scheme!), nor are they all the same thing (so, no Scheme null?, but
> could have empty?).

Yes, I think an empty? predicate would be a good thing.

> I guess the short answer is there's no 'false' because that is not how
> Clojure works, and Clojure works differently than both CL and Scheme.

Most Schemes do provide a null separate from #f; in Chicken it's
the result of calling "void", and it's mapped to NULL in SQL and to
nil in Lua, both of which distinguish between false and null.
In other Schemes, you can usually capture it by evaluating
(if #f #f), though by the letter of R5RS this could return 47
or something.

> eql? is not great. You're right, CLers might expect eql, and as far as
> Clojure and its data structures, eql? is mostly the same as Scheme
> equal? (although one could argue that the ability of equal? to return
> true for mutable objects in Scheme is an error - see
> http://home.pipeline.com/~hbaker1/ObjectIdentity.html).

I thought about that quite a lot, and concluded that although Java equals()
is inconsistently implemented, it basically represents "contingent equality",
whereas egal represents "necessary equality". For example, two
StringBuffers are equals() in Java iff they happen to contain the same
characters at the moment of call, whereas because they are mutable
they could never be egal.

But it seems to me that equals() is mostly an upward compatible
extension of Scheme equal?, and should be so named. You could
only do egal in Java if there were some way of distinguishing value
classes from object classes, which there isn't. (On the .NET
platform, though, ...)

> I wanted to use ==, but am afraid that Java programmers will
> expect a reference comparison. egal seemed too weird. Open to
> suggestions (but suggesters should read Baker's paper first, please).

Yes, I think that would confuse the bejesus out of everyone. OTOH,
the name of Java == should be, I think, eqv? or just eq? (you can
make them the same, it's implementation-dependent), as that's
exactly what it does.

[later posting]

> > any example I could give of
> > parallel let usage could be made into a sequential let usage by
> > prepending all the names with 'new-' or similar.
>
> And probably should be renamed.

(rant "I and Dijkstra, and probably nobody else, believes that being able to
shadow outer variable names with inner ones is just a mistake, and
shouldn't be allowed. Python is sort of like this with the global
statement, but that's only when assignment is needed; I'd like to
say that *no* outer variable is available in an inner scope unless
(re)declared in that scope, for reasonably large values of
'scope'.")

> > Why no '?' if it is solely a predicate?
>
>
> == is a nice operator and people will expect it to do something, so it
> does what Java's does, for numbers only. Like Scheme's = has no "?"

Indeed, no Lisp has ever used ? on the numeric comparison
predicates. But I'd rather see = than ==. This is Lisp, after all, not
some language abortion that reserves = for assignment!

Rich Hickey

unread,
Dec 6, 2007, 11:34:45 AM12/6/07
to Clojure


On Dec 5, 5:56 pm, "John Cowan" <johnwco...@gmail.com> wrote:
> On Dec 5, 2007 10:54 AM, Rich Hickey <richhic...@gmail.com> wrote:
>
> > recur is in Clojure for a very specific reason - it, and only it, is
> > guaranteed to turn into a non-stack-consuming loop. In the absence of
> > a full TCO promise, and any other looping construct, it is essential
> > people know when they are going to get a loop. named-let is not the
> > same - a call to the named function can appear in a non-tail position,
> > and the function object can be passed/returned.
>
> I don't consider those huge problems, especially not allowing the
> function to escape. However, it would be useful to be able to
> recur an outer loop from within an inner loop, which named let
> would allow (or does that not work for implementation reasons)?
>

I have considered named loop, will think more about it.

> So when you call a Java method from Clojure code, you map nil
> to false if the argument is boolean, and to null if it's an object?

Yes.

> (Theoretically there would be a problem if the argument is
> java.lang.Boolean, I guess, since null would be valid.)
>

Not really - Booleans are not booleans.

> > Empty collections are not nothing (so they are conditional true, like
> > Scheme!), nor are they all the same thing (so, no Scheme null?, but
> > could have empty?).
>
> Yes, I think an empty? predicate would be a good thing.
>

I'm just afraid of a lot of (if (not (empty? x))..., where (if (seq
x)... would be my preferred idiom for Clojure code.

As I said elsewhere, empty? ==> not seq

> Most Schemes do provide a null separate from #f; in Chicken it's
> the result of calling "void", and it's mapped to NULL in SQL and to
> nil in Lua, both of which distinguish between false and null.
> In other Schemes, you can usually capture it by evaluating
> (if #f #f), though by the letter of R5RS this could return 47
> or something.
>

The real issue is what rest returns, as discussed previously.

> > eql? is not great. You're right, CLers might expect eql, and as far as
> > Clojure and its data structures, eql? is mostly the same as Scheme
> > equal? (although one could argue that the ability of equal? to return
> > true for mutable objects in Scheme is an error - see
> >http://home.pipeline.com/~hbaker1/ObjectIdentity.html).
>
> I thought about that quite a lot, and concluded that although Java equals()
> is inconsistently implemented, it basically represents "contingent equality",
> whereas egal represents "necessary equality". For example, two
> StringBuffers are equals() in Java iff they happen to contain the same
> characters at the moment of call, whereas because they are mutable
> they could never be egal.
>

Actually, 2 StringBuffers with identical contents are not equals(). If
they were, I would consider them broken.

> But it seems to me that equals() is mostly an upward compatible
> extension of Scheme equal?, and should be so named. You could
> only do egal in Java if there were some way of distinguishing value
> classes from object classes, which there isn't. (On the .NET
> platform, though, ...)

[The notion of 'value type' in .Net is more about allocation than
immutability. Heap-allocated values types are quite useful - Clojure
is full of them. Yes, some way to identify them would be useful]

It's more than a philosophical point. IMO, egal or its moral
equivalent is the only notion of composite value equality that has any
utility in multithreaded programming, and that's the notion of
equality I want for Clojure. My reading of Scheme equal? (the R5RS
definition of its behavior as a comparison of the _contents_ of
[mutable] pair, strings and vectors) implies that, in Clojure, 2 Ref
(or Var or Agent) objects containing equal? values should return
equal? => true. They don't, and won't, because they are mutable.

I'll stick with eql? for now, and probably move to = at some point
soon.

Rich

John Cowan

unread,
Dec 6, 2007, 4:24:31 PM12/6/07
to clo...@googlegroups.com
On Dec 6, 2007 11:34 AM, Rich Hickey <richh...@gmail.com> wrote:

> > (Theoretically there would be a problem if the argument is
> > java.lang.Boolean, I guess, since null would be valid.)
>
> Not really - Booleans are not booleans.

Hmm. You don't autobox primitive types when calling Java methods,
then?

> Actually, 2 StringBuffers with identical contents are not equals(). If
> they were, I would consider them broken.

Sorry, you're right. I was thinking of Hashtables (or Maps generally),
which are equals() by contract iff they have the same mapping.
For that matter, the same is true of Lists and Sets.

> It's more than a philosophical point. IMO, egal or its moral
> equivalent is the only notion of composite value equality that has any
> utility in multithreaded programming,

I agree. (OTOH, I think that multithreaded programming with
shared data is an abomination.)

> I'll stick with eql? for now, and probably move to = at some point
> soon.

Okay.

Rich Hickey

unread,
Dec 6, 2007, 5:17:55 PM12/6/07
to Clojure


On Dec 6, 4:24 pm, "John Cowan" <johnwco...@gmail.com> wrote:
> On Dec 6, 2007 11:34 AM, Rich Hickey <richhic...@gmail.com> wrote:
>
> > > (Theoretically there would be a problem if the argument is
> > > java.lang.Boolean, I guess, since null would be valid.)
>
> > Not really - Booleans are not booleans.
>
> Hmm. You don't autobox primitive types when calling Java methods,
> then?
>

I think we might be missing each other here - Clojure does what's
needed to get to from the Java primitives when used as arguments and
returns. Are you talking about methods which take Integer, Boolean,
Long et al wrapper classes explicitly? Are there many? No conversion
is done to/from args of explicit wrapper types right now.

> > Actually, 2 StringBuffers with identical contents are not equals(). If
> > they were, I would consider them broken.
>
> Sorry, you're right. I was thinking of Hashtables (or Maps generally),
> which are equals() by contract iff they have the same mapping.
> For that matter, the same is true of Lists and Sets.
>

That's why Clojure offers its own collections.

> > It's more than a philosophical point. IMO, egal or its moral
> > equivalent is the only notion of composite value equality that has any
> > utility in multithreaded programming,
>
> I agree. (OTOH, I think that multithreaded programming with
> shared data is an abomination.)
>

Even immutable data?

John Cowan

unread,
Dec 6, 2007, 5:25:38 PM12/6/07
to clo...@googlegroups.com
On Dec 6, 2007 5:17 PM, Rich Hickey <richh...@gmail.com> wrote:

> Are you talking about methods which take Integer, Boolean,
> Long et al wrapper classes explicitly?

Yes.

> Are there many?

Probably few or none.

> > I agree. (OTOH, I think that multithreaded programming with
> > shared data is an abomination.)
>
> Even immutable data?

No.

Mathias Dahl

unread,
Dec 6, 2007, 6:53:48 PM12/6/07
to Clojure
> I recently gave a talk on Clojure to the LispNYC group. Audio and
> slides from the talk are now available online:
>
> http://lispnyc.org/wiki.clp?page=past-meetings

Great talk! I have been listening to it on my bike, to and from work,
the last couple of days, and I still need to listen to it a couple of
times more so that I can digest more of all interesting topics you
bring up. You seem to know what you are talking about.

/Mathias

Rich Hickey

unread,
Dec 7, 2007, 9:41:13 AM12/7/07
to Clojure


On Dec 5, 1:04 pm, "Henk Boom" <lunarcri...@gmail.com> wrote:
> Also, currently I don't see an easy way of telling when a key is
> mapped to nil in hash-tables. In PLT-Scheme the hash-table lookup
> function takes an optional argument which is the value to return when
> the key is not found. Should this be implemented?
>

Done. (get map key not-found) works.


> (Also^2, if maps are seqs, I would expect to be able (key (first m))
> and (value (first m)) to extract information from them. 'values' and
> keys' don't seem really useful to me once that works. Currently it
> seems that (first m) and (rest m) do not produce useful results.)
>

Done. All Clojure map entries implement Map.Entry and key and val
functions are defined that work on any Map.Entry.

In SVN, will be in next release.

Rich
Reply all
Reply to author
Forward
0 new messages