Re: Creating a PrintWriter: No matching ctor found

872 views
Skip to first unread message
Message has been deleted

Toralf Wittner

unread,
Jan 3, 2008, 4:02:43 PM1/3/08
to clo...@googlegroups.com
On Thu, 2008-01-03 at 08:10 -0800, Chas Emerick wrote:
> Simple enough. However:
>
> user=> (new PrintWriter (new ByteArrayOutputStream) :t)
> java.lang.IllegalArgumentException: No matching ctor found
> at clojure.lang.Reflector.invokeConstructor(Unknown Source)
> at clojure.lang.Compiler$NewExpr.eval(Unknown Source)
> at clojure.lang.Compiler.eval(Unknown Source)
> at clojure.lang.Repl.main(Unknown Source)
>

AFAICS :t is of class clojure.lang.Keyword and when the Reflector
searches for the right constructor to invoke it can not find one in
class java.io.PrintWriter whose second parameter is of type
clojure.lang.Keyword. Note that this also affects (. Boolean TRUE) which
is mapped to :t as well.

Reflector.isCongruent() checks the parameters against the supplied
arguments and in case of a boolean parameter it checks whether the
argument is null or of class Boolean. Adding a check arg == RT.T (which
is the internal representation of :t) might fix the problem I think (and
also for overloaded methods which contain boolean parameters).

Cheers,
Toralf


Chas Emerick

unread,
Jan 3, 2008, 6:41:03 PM1/3/08
to Clojure
Odd that my original post seems to be gone....

Anyway -- yes, the fix you suggested works, and now (new Boolean :t)
works as well (a much simpler testcase). Rich, here's a patch
(overkill I guess):

Index: src/jvm/clojure/lang/Reflector.java
===================================================================
--- src/jvm/clojure/lang/Reflector.java (revision 594)
+++ src/jvm/clojure/lang/Reflector.java (working copy)
@@ -320,7 +320,7 @@
Class paramType = params[i];
if(paramType == boolean.class)
{
- ret = arg == null || argType ==
Boolean.class;
+ ret = arg == null || argType ==
Boolean.class || arg == RT.T;
}
else if(paramType.isPrimitive())
{

- Chas

Rich Hickey

unread,
Jan 3, 2008, 10:56:45 PM1/3/08
to Clojure
This now works:

(new PrintWriter (new ByteArrayOutputStream) (boolean :t))

Not using your fix, the problem was elsewhere.

Rich

Toralf Wittner

unread,
Jan 4, 2008, 10:59:42 AM1/4/08
to clo...@googlegroups.com

However the current state with regards to :t seems somewhat inconsistent
to me. It is not possible to do (new Boolean :t) but something like (.
(new javax.swing.JFrame "Test") (setVisible :t)) is ok, (. Boolean
(valueOf :t)) again is not.

Also note that (new Boolean nil) throws an exception:

user=> (new Boolean nil)
clojure.lang.Compiler$CompilerException: REPL:1: null
at clojure.lang.Compiler.analyzeSeq(Unknown Source)
at clojure.lang.Compiler.analyze(Unknown Source)
at clojure.lang.Compiler.analyze(Unknown Source)


at clojure.lang.Compiler.eval(Unknown Source)
at clojure.lang.Repl.main(Unknown Source)

Caused by: java.lang.NullPointerException
at java.lang.Class.isAssignableFrom(Native Method)
at clojure.lang.Reflector.paramArgTypeMatch(Unknown Source)
at clojure.lang.Compiler.getMatchingParams(Unknown Source)
at clojure.lang.Compiler$NewExpr.<init>(Unknown Source)
at clojure.lang.Compiler$NewExpr$Parser.parse(Unknown Source)
... 5 more

I think the patch Chas posted is still valid because you can then use
nil or :t without type casts. If the NPE in Reflector.paramArgTypeMatch
is fixed, e.g. by putting "if(argType == null) return true;" in the
first line (I think this is justified because null is a valid member of
every type)) then one can do:

user=> (new Boolean :t)
true
user=> (new Boolean nil)
false
user=> (. Boolean (valueOf :t))
true
user=> (. Boolean (valueOf nil))
nil
user=> (new Boolean (boolean :t))
true
user=> (new Boolean (boolean nil))
false
user=> (. Boolean (valueOf (boolean :t)))
true
user=> (. Boolean (valueOf (boolean nil)))
nil
user=> (. (new javax.swing.JFrame "Test") (setVisible :t))
nil
user=> (. (new javax.swing.JFrame "Test") (setVisible nil))
nil

Cheers,
Toralf

bool.diff

Rich Hickey

unread,
Jan 4, 2008, 2:06:48 PM1/4/08
to Clojure


On Jan 4, 10:59 am, Toralf Wittner <toralf.witt...@gmail.com> wrote:
> On Thu, 2008-01-03 at 19:56 -0800, Rich Hickey wrote:
> > This now works:
>
> > (new PrintWriter (new ByteArrayOutputStream) (boolean :t))
>
> > Not using your fix, the problem was elsewhere.
>
> However the current state with regards to :t seems somewhat inconsistent
> to me.

I understand. Please bear with me. I'm in the middle of working on
improving the overload resolution logic, in particular the cases
where methods were overloaded with the same arity, which always
generated reflective calls. In addition, I am working on unifying the
reflective and compiled calls so they have the same behavior - many
people are tripping over differences.

When I am done the following should be true:

1) Reflective and compiled calls will behave the same.
2) Many more calls will non-reflective, given minimal hints.
3) Implicit conversion to boolean is going away.

The need for #3 is demonstrated by your (new Boolean nil) call - there
is no reason it should resolve to the boolean overload versus the
String overload.

I've made great progress on #2 - now in all the code generated by
compiling boot.clj there are only 3 reflective calls! And I don't
consider boot.clj to be overburdened with type hints.

So, please hang tight, I should be done within a few checkins and then
I'll explain further.

Rich

Chas Emerick

unread,
Jan 5, 2008, 1:21:58 AM1/5/08
to Clojure
Rich, sorry for perhaps jumping the gun on you. FWIW, I'd say all of
this enthusiasm reflects pretty well on the work you've done (and
continue to do) to bring Clojure to where it is....

- Chas

Toralf Wittner

unread,
Jan 5, 2008, 8:55:25 AM1/5/08
to clo...@googlegroups.com
On Fri, 2008-01-04 at 11:06 -0800, Rich Hickey wrote:
> I understand. Please bear with me. I'm in the middle of working on
> improving the overload resolution logic, in particular the cases
> where methods were overloaded with the same arity, which always
> generated reflective calls. In addition, I am working on unifying the
> reflective and compiled calls so they have the same behavior - many
> people are tripping over differences.
>

Sorry for jumping the gun on this subject - I wasn't aware that this
part is being revised.

> 3) Implicit conversion to boolean is going away.
>
> The need for #3 is demonstrated by your (new Boolean nil) call - there
> is no reason it should resolve to the boolean overload versus the
> String overload.

Hmm. I confess I'm a bit puzzled by this whole boolean thing. I like the
Scheme way of having #t for true and #f for false. Since in Clojure nil
is used to represent false and null it seems to me that treating nil as
a boolean is only logical ;-) So expecting (new Boolean nil) to resolve
to the boolean overload follows directly from nil denoting boolean
falsity. On the other hand the need to typecast nil to boolean looks
weird to me. I wonder what's the advantage of having nil meaning false
and null? Wouldn't it be better to copy Scheme and having a dedicated
false value, e.g. :f which leaves nil for null?

>
> I've made great progress on #2 - now in all the code generated by
> compiling boot.clj there are only 3 reflective calls! And I don't
> consider boot.clj to be overburdened with type hints.
>

Excellent work! I appreciate it very much that you put so much energy
into Clojure. It shows.

Thanks,
Toralf


Frantisek Sodomka

unread,
Jan 5, 2008, 9:16:27 AM1/5/08
to clo...@googlegroups.com
On Sat, 05 Jan 2008 14:55:25 +0100, Toralf Wittner
<toralf....@gmail.com> wrote:

>> 3) Implicit conversion to boolean is going away.
>>
>> The need for #3 is demonstrated by your (new Boolean nil) call - there
>> is no reason it should resolve to the boolean overload versus the
>> String overload.
>
> Hmm. I confess I'm a bit puzzled by this whole boolean thing. I like the
> Scheme way of having #t for true and #f for false. Since in Clojure nil
> is used to represent false and null it seems to me that treating nil as
> a boolean is only logical ;-) So expecting (new Boolean nil) to resolve
> to the boolean overload follows directly from nil denoting boolean
> falsity. On the other hand the need to typecast nil to boolean looks
> weird to me. I wonder what's the advantage of having nil meaning false
> and null? Wouldn't it be better to copy Scheme and having a dedicated
> false value, e.g. :f which leaves nil for null?

Yes, sometimes I also wonder if having 'nil' for both false and null is a
good thing. Could you explain more?

Maybe it would make sense to change ':t' to 'true'. It goes well with
'nil' and you free up keyword ':t'.

I am using newLISP for some of my projects, so feel free to see:
http://www.newlisp.org/
http://www.newlisp.org/index.cgi?Documentation
http://www.newlisp.org/downloads/newlisp_manual.html

Happy coding, Frantisek :-)

John Cowan

unread,
Jan 5, 2008, 10:35:30 AM1/5/08
to clo...@googlegroups.com
On Jan 5, 2008 8:55 AM, Toralf Wittner <toralf....@gmail.com> wrote:

> Wouldn't it be better to copy Scheme and having a dedicated
> false value, e.g. :f which leaves nil for null?

I very strongly agree. It took Scheme until R4RS to get #f and ()
completely disentangled, and everyone in the community agrees that it
was a Good Thing. A few adjustments had to be made: for example,
assoc now returns a cons if it finds something or #f if it finds
nothing, since people were treating the result as boolean quite
frequently.

Similarly, it took the C lineage until Java to get false and 0 and
null disentangled, and I don't know any Java programmer who thinks
that was a mistake. It catches a huge number of errors right away.
(Java and Scheme differ, though, in that anything not #f is still true
in Scheme, whereas it's an error to use anything other than true or
false in conditional contexts in Java.)

Since Clojure does not have to be backward compatible with anything, it should
separate the empty sequence from falsity right away.

> > I've made great progress on #2 - now in all the code generated by
> > compiling boot.clj there are only 3 reflective calls! And I don't
> > consider boot.clj to be overburdened with type hints.

Which ones are they?

> Excellent work! I appreciate it very much that you put so much energy
> into Clojure. It shows.

I also agree very strongly with that.

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

Rich Hickey

unread,
Jan 5, 2008, 10:48:03 AM1/5/08
to Clojure


On Jan 5, 8:55 am, Toralf Wittner <toralf.witt...@gmail.com> wrote:

> Hmm. I confess I'm a bit puzzled by this whole boolean thing. I like the
> Scheme way of having #t for true and #f for false. Since in Clojure nil
> is used to represent false and null it seems to me that treating nil as
> a boolean is only logical ;-) So expecting (new Boolean nil) to resolve
> to the boolean overload follows directly from nil denoting boolean
> falsity. On the other hand the need to typecast nil to boolean looks
> weird to me. I wonder what's the advantage of having nil meaning false
> and null? Wouldn't it be better to copy Scheme and having a dedicated
> false value, e.g. :f which leaves nil for null?
>

You can't simply look at one facet of a language in isolation. nil,
Java null, conditionals and sequences all interact.

Please read this message, if you haven't yet:

http://groups.google.com/group/clojure/msg/ced660e69fd2aa0b

Also this:

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

Scheme #t is almost completely meaningless, as Scheme conditionals
test for #f/non-#f, not #f/#t. I don't think the value #f has much
utility whatsoever, and basing conditionals on it means writing a lot
of (if (not (null? x))... where (if x... will do in Clojure/CL, and a
substantial reduction in expressive power when dealing with sequences,
filters etc.

I realize that people coming from Scheme might not see the value, but
it's there and I'm not willing to do without it.

I recommend everyone try to understand why Clojure is the way it is
rather than suggesting it become like Scheme in this area - it's not
going to happen.

I am happy to continue to explain how Clojure works and why, and am
prepping a little spreadsheet showing what Clojure/Common Lisp/Scheme
do in these areas to help provide semantic mappings and facilitate
understanding the differences.

Rich

Rich Hickey

unread,
Jan 5, 2008, 11:22:15 AM1/5/08
to Clojure


On Jan 5, 10:35 am, "John Cowan" <johnwco...@gmail.com> wrote:
> On Jan 5, 2008 8:55 AM, Toralf Wittner <toralf.witt...@gmail.com> wrote:
>
> > Wouldn't it be better to copy Scheme and having a dedicated
> > false value, e.g. :f which leaves nil for null?
>
> I very strongly agree. It took Scheme until R4RS to get #f and ()
> completely disentangled, and everyone in the community agrees that it
> was a Good Thing. A few adjustments had to be made: for example,
> assoc now returns a cons if it finds something or #f if it finds
> nothing, since people were treating the result as boolean quite
> frequently.
>

Making its return type inconsistent.

> Similarly, it took the C lineage until Java to get false and 0 and
> null disentangled, and I don't know any Java programmer who thinks
> that was a mistake. It catches a huge number of errors right away.

I agree about 0, but not null - I would greatly prefer if conditional
tests in Java tested for null and that falsity/null were conflated. I
find boolean values to be very information-poor. I'd much rather
return null/something-substantial than true/false.

> (Java and Scheme differ, though, in that anything not #f is still true
> in Scheme, whereas it's an error to use anything other than true or
> false in conditional contexts in Java.)
>

Which shows that the Scheme folks appreciate the value of punning,
else they would have gone pure with conditionals testing for #f/#t and
the further reduction in information that entails. There's no right or
wrong, it's just a matter of where you draw the line, and I find that
CL draws the line at a more practical point than Scheme, IMO, YMMV
etc :)

> Since Clojure does not have to be backward compatible with anything, it should
> separate the empty sequence from falsity right away.
>

There is no such thing as the empty sequence - there is either a
sequence or there isn't one. There are empty collections in Clojure
and they are distinct from nil.

> > > I've made great progress on #2 - now in all the code generated by
> > > compiling boot.clj there are only 3 reflective calls! And I don't
> > > consider boot.clj to be overburdened with type hints.
>
> Which ones are they?
>

I'm not telling (yet :)

When I have this sewn up I will provide a flag that one can set in
order to be told when you are _not_ getting direct compiled calls, to
aid in type-hinting optimization.

> > Excellent work! I appreciate it very much that you put so much energy
> > into Clojure. It shows.
>
> I also agree very strongly with that.
>

Thanks.

Rich

Toralf Wittner

unread,
Jan 5, 2008, 1:37:52 PM1/5/08
to clo...@googlegroups.com
On Sat, 2008-01-05 at 07:48 -0800, Rich Hickey wrote:
> On Jan 5, 8:55 am, Toralf Wittner <toralf.witt...@gmail.com> wrote:
> > Wouldn't it be better to copy Scheme and having a dedicated
> > false value, e.g. :f which leaves nil for null?
>
> You can't simply look at one facet of a language in isolation. nil,
> Java null, conditionals and sequences all interact.
[...]

> I recommend everyone try to understand why Clojure is the way it is
> rather than suggesting it become like Scheme in this area - it's not
> going to happen.

Agreed. I certainly didn't want to appear fanatic about this topic and I
see the advantages of nil with regards to sequences and conditional
tests. I was just confused by the new requirement to explicitly typecast
(boolean nil) when interacting with the host. This however seems
inevitable because of nil's dual nature which differs from Java's
treatment of null and false. This in turn lead me to look at Scheme's #f
but yes, I agree that exclusively using a single value for logical
falsity would cost expressiveness and given the choice I also prefer a
more expressive Clojure.

So, withdrawing my question about copying Scheme in this area, I would
like to ask another (possibly foolish) one instead--would it make sense
to introduce a second value for logical falsity, so having :t/:f and
being able to use them directly as booleans with Java and still having
nil as it is now?

Thanks,
Toralf


Toralf

unread,
Jan 5, 2008, 1:55:54 PM1/5/08
to Clojure
On Jan 5, 7:37 pm, Toralf Wittner <toralf.witt...@gmail.com> wrote:
> So, withdrawing my question about copying Scheme in this area, I would
> like to ask another (possibly foolish) one instead--would it make sense
> to introduce a second value for logical falsity, so having :t/:f and
> being able to use them directly as booleans with Java and still having
> nil as it is now?

To answer my own (indeed foolish) question - no. I had a misconception
about :t, thinking of it as something special which it isn't. Sorry
for confusing things (thanks Rich for the spreadsheet).

Cheers,
Toralf

Rich Hickey

unread,
Jan 5, 2008, 2:36:25 PM1/5/08
to Clojure
If you look at the spreadsheet there are only two open slots for
Clojure in this area - the values to represent Java's true and false
primitives in argument matching, since implicit conversions of Clojure
logical values are incompatible with overloading. I am considering
supplying constants that correspond to the values Boolean.TRUE and
Boolean.FALSE for use in _calling_ Java, but I won't change the nature
of conditional tests to also test for FALSE - it's a performance issue
I decided long ago.

I personally would have no problem with them being called true/false,
TRUE/FALSE etc, but I'm comfortable with the meaning of conditional
tests being nil-based and not boolean based. I'm concerned that
newcomers will have incorrect suppositions about the behavior of (if
FALSE ...).

I'm open to suggestion for names, given:

- They will represent Boolean.TRUE and Boolean.FALSE, and will have
type Boolean

- only Booleans will implicitly convert to match boolean arguments in
calls to Java, as now

- Conditionals will test for nil/non-nil, as now

- boolean returns from Java will be converted into nil/:t, as now

- the boolean coercion operator will still be available to transform
Clojure logical values to Java logical values, as now

Rich

John Cowan

unread,
Jan 5, 2008, 4:01:14 PM1/5/08
to clo...@googlegroups.com
On Jan 5, 2008 2:36 PM, Rich Hickey <richh...@gmail.com> wrote:

> - They will represent Boolean.TRUE and Boolean.FALSE, and will have
> type Boolean
>
> - only Booleans will implicitly convert to match boolean arguments in
> calls to Java, as now
>
> - Conditionals will test for nil/non-nil, as now
>
> - boolean returns from Java will be converted into nil/:t, as now
>
> - the boolean coercion operator will still be available to transform
> Clojure logical values to Java logical values, as now

Then I suggest "javatrue" and "javafalse", or any shortening or
punctuating of that (jtrue, java-true, whatever) that suits you.

I would also suggest a convenience function "javatruth" that maps
nil/non-nil to javafalse and javatrue, so you can say things like
(java-function (javatruth (another-java-function)))
where java-function expects a Boolean and another-java-function returns one.

Rich Hickey

unread,
Jan 5, 2008, 4:26:29 PM1/5/08
to Clojure


On Jan 5, 10:35 am, "John Cowan" <johnwco...@gmail.com> wrote:
> On Jan 5, 2008 8:55 AM, Toralf Wittner <toralf.witt...@gmail.com> wrote:

> > > I've made great progress on #2 - now in all the code generated by
> > > compiling boot.clj there are only 3 reflective calls! And I don't
> > > consider boot.clj to be overburdened with type hints.
>
> Which ones are they?
>

Now - None!

Rich Hickey

unread,
Jan 5, 2008, 4:31:57 PM1/5/08
to Clojure


On Jan 5, 4:01 pm, "John Cowan" <johnwco...@gmail.com> wrote:
> On Jan 5, 2008 2:36 PM, Rich Hickey <richhic...@gmail.com> wrote:
>
> > - They will represent Boolean.TRUE and Boolean.FALSE, and will have
> > type Boolean
>
> > - only Booleans will implicitly convert to match boolean arguments in
> > calls to Java, as now
>
> > - Conditionals will test for nil/non-nil, as now
>
> > - boolean returns from Java will be converted into nil/:t, as now
>
> > - the boolean coercion operator will still be available to transform
> > Clojure logical values to Java logical values, as now
>
> Then I suggest "javatrue" and "javafalse", or any shortening or
> punctuating of that (jtrue, java-true, whatever) that suits you.
>
> I would also suggest a convenience function "javatruth" that maps
> nil/non-nil to javafalse and javatrue, so you can say things like
> (java-function (javatruth (another-java-function)))
> where java-function expects a Boolean and another-java-function returns one.

That's what the boolean coercion op does now. Note that this won't be
needed unless the calls are reflective.


Rich

Toralf Wittner

unread,
Jan 5, 2008, 5:50:34 PM1/5/08
to clo...@googlegroups.com
On Sat, 2008-01-05 at 11:36 -0800, Rich Hickey wrote:
> I am considering
> supplying constants that correspond to the values Boolean.TRUE and
> Boolean.FALSE for use in _calling_ Java, but I won't change the nature
> of conditional tests to also test for FALSE - it's a performance issue
> I decided long ago.
>

Not to question your decision but what do you estimate how big the
performance impact would be?

> I personally would have no problem with them being called true/false,
> TRUE/FALSE etc, but I'm comfortable with the meaning of conditional
> tests being nil-based and not boolean based. I'm concerned that
> newcomers will have incorrect suppositions about the behavior of (if
> FALSE ...).

I would certainly have tried that. :D
Now how to prevent this I don't know. It has to be made clear in the
documentation what TRUE and FALSE are meant for and using non-obvious
names for TRUE and FALSE would probably cause users to read the docs
after they tried the usual suspects but no one likes non-obvious names
for TRUE and FALSE since they are meant to be a convenience.

Thanks,
Toralf


Stuart Sierra

unread,
Jan 5, 2008, 11:34:49 PM1/5/08
to clo...@googlegroups.com
On Sat, 2008-01-05 at 11:36 -0800, Rich Hickey wrote:
> I am considering
> supplying constants that correspond to the values Boolean.TRUE and
> Boolean.FALSE for use in _calling_ Java, but I won't change the nature
> of conditional tests to also test for FALSE - it's a performance issue
> I decided long ago.

Just my 2 cents: I like Ruby's "true", "false", and "nil" keywords.
Ruby treats both "false" and "nil" as false in boolean expressions;
anything else is considered true. It's very clear when you're
returning a boolean value, but you still get the convenience of using
nil in boolean expressions.

Having true/false/nil map exactly to Java true/false/null (boxed if
necessary) would avoid confusion over the type conversions.

-Stuart

Rich Hickey

unread,
Jan 6, 2008, 9:37:45 AM1/6/08
to Clojure


On Jan 5, 11:34 pm, "Stuart Sierra" <the.stuart.sie...@gmail.com>
wrote:
That's what I concluded after sleeping on it last night.

I have 2 concerns.

The first is performance. The last time I looked into it though, I was
trying to fully support all Boolean objects, which requires an
instance test, a checkcast, and a function call. If I limit it to
adding a test for Boolean.FALSE identity it might not be too bad.

The second is correct use. I find the Scheme functions returning
something/#f (e.g. member, assoc ) quite wrong, and an indictment of
the whole notion of a boolean type in Scheme. I think functions should
return something or nothing (nil). 'something' can be a boolean, in
which case the expected values should be _only_ true, false or nil. So
none of the seq functions should return false (except true predicates
- every et al). But I can't stop others from doing the wrong thing
and creating a mess.

The latter is a minimal argument against naming them #t and #f.

I'm going to explore this. Input welcome.

Rich

Henk Boom

unread,
Jan 6, 2008, 1:00:21 PM1/6/08
to clo...@googlegroups.com
On 06/01/2008, Rich Hickey <richh...@gmail.com> wrote:
> The second is correct use. I find the Scheme functions returning
> something/#f (e.g. member, assoc ) quite wrong, and an indictment of
> the whole notion of a boolean type in Scheme. I think functions should
> return something or nothing (nil). 'something' can be a boolean, in
> which case the expected values should be _only_ true, false or nil. So
> none of the seq functions should return false (except true predicates
> - every et al). But I can't stop others from doing the wrong thing
> and creating a mess.

I understand that you (along with many lispers) thing about this
differently. I just want to explain the thought process which
justifies #f, at least for me.

As a schemer, I always saw #f and null (or '()) as two different types
of nothing. #f was really nothing, and null was the list containing no
elements. For example, if I have a string->numbers which converts "1,
2, 3" to (1 2 3), a return value of #f would mean "That string is not
parsable as a list of numbers", while null would mean "I parsed that
string as containing no numbers". I feel uncomfortable when 'nothing'
is indistinguishable from 'a list containing no elements'. A return
type of 'something or nothing' makes sense to me. 'A list containing
elements or a list containing no elements' makes sense to me. 'A list
or nothing' makes sense to me (this cannot be done with nil, as lists
and nothing overlap). 'something or a list containing no elements'
seems like a stretch of logic.

Just my two pieces of sense,
Henk

Rich Hickey

unread,
Jan 6, 2008, 1:21:06 PM1/6/08
to Clojure


On Jan 6, 1:00 pm, "Henk Boom" <lunarcri...@gmail.com> wrote:

Rich Hickey

unread,
Jan 6, 2008, 1:51:05 PM1/6/08
to Clojure


On Jan 6, 1:00 pm, "Henk Boom" <lunarcri...@gmail.com> wrote:
Welcome back, Henk!

I'm not sure we're far off here although the names are different.

In Clojure nil means 'nothing'

false (now) means one of the two possible boolean values, the other
being true

There is more to collections than lists. You can have instances of
empty collections, some of which have literal support ([], {}, and
()). Thus there can be no sentinel empty collection value.

Empty collections are distinct from nil. Clojure does not equate nil
and '().

So nil maps most closely to your notion of #f than anything else. You
could write your string->numbers function in Clojure returning (1 2
3), () (no numbers), or nil (not parseable). i.e. as a function that
returns a list, rather than as a function that returns a seq.

The big difference, and novelty in Clojure, is sequences. Sequences
are not collections, esp. they are not lists. There is no such thing
as an empty sequence. Either there is a sequence (with elements) or
there isn't (nil). When you ask an empty collection for a sequence of
its elements it returns nil, saying "I can't produce one". When you
ask a sequence on its last element for the rest it returns nil,
saying, "there is no more".

Some of the sequence function map to functions from Scheme and CL that
there manipulated only pairs/conses ("lists") and returned sentinel
values ('() and nil) that represented 'empty' lists. The Clojure
return values differ in not returning empty collections, but rather a
sequence or not. Some of the sequence functions have no counterpart in
Scheme/CL, and map to Haskell/ML-like functions. Some of those
functions return infinite or calculated sequences, where the analogy
to concrete data-structures like lists is tenuous at best.

I think the leap is in distinguishing collections/data-structures and
seqs/iteration. In both CL and Scheme they are conflated, in Clojure
they are separate.

I'm interested in what you think of the true/false support and whether
the spreadsheet helps.

Thanks for the feedback,

Rich

John Cowan

unread,
Jan 6, 2008, 5:25:00 PM1/6/08
to clo...@googlegroups.com
On Jan 6, 2008 1:51 PM, Rich Hickey <richh...@gmail.com> wrote:

> I'm not sure we're far off here although the names are different.

What follows should go on the website.

Rich Hickey

unread,
Jan 7, 2008, 7:15:03 AM1/7/08
to Clojure


On Jan 6, 5:25 pm, "John Cowan" <johnwco...@gmail.com> wrote:
> On Jan 6, 2008 1:51 PM, Rich Hickey <richhic...@gmail.com> wrote:
>
> > I'm not sure we're far off here although the names are different.
>
> What follows should go on the website.
>

I've added it, thanks.

MikeM

unread,
Jan 7, 2008, 3:27:11 PM1/7/08
to Clojure


On Jan 6, 1:51 pm, Rich Hickey <richhic...@gmail.com> wrote:
>
> The big difference, and novelty in Clojure, is sequences. Sequences
> are not collections, esp. they are not lists. There is no such thing
> as an empty sequence. Either there is a sequence (with elements) or
> there isn't (nil). When you ask an empty collection for a sequence of
> its elements it returns nil, saying "I can't produce one". When you
> ask a sequence on its last element for the rest it returns nil,
> saying, "there is no more".
>

You've stated in a few messages "there is no such thing as an empty
sequence", and I'm wondering why this is important. In your docs
(http://clojure.sourceforge.net/reference/sequences.html) there is
this:"Note that generally the first item is always produced, in order
to determine if in fact there is a sequence at all..." This seems to
be saying that you can have an object that implements the sequence
interface but it may not have any elements. Isn't this an empty
sequence?

Rich Hickey

unread,
Jan 7, 2008, 4:01:39 PM1/7/08
to Clojure


On Jan 7, 3:27 pm, MikeM <michael.messini...@invista.com> wrote:
> On Jan 6, 1:51 pm, Rich Hickey <richhic...@gmail.com> wrote:
>
>
>
> > The big difference, and novelty in Clojure, is sequences. Sequences
> > are not collections, esp. they are not lists. There is no such thing
> > as an empty sequence. Either there is a sequence (with elements) or
> > there isn't (nil). When you ask an empty collection for a sequence of
> > its elements it returns nil, saying "I can't produce one". When you
> > ask a sequence on its last element for the rest it returns nil,
> > saying, "there is no more".
>
> You've stated in a few messages "there is no such thing as an empty
> sequence", and I'm wondering why this is important.

It's important to those that want to distinguish an empty list from
logical false/nothing. In CL you can't, in Scheme you can. In Clojure
you can, once you distinguish seqs from collections.

> In your docs
> (http://clojure.sourceforge.net/reference/sequences.html) there is
> this:"Note that generally the first item is always produced, in order
> to determine if in fact there is a sequence at all..." This seems to
> be saying that you can have an object that implements the sequence
> interface but it may not have any elements.

Not quite. There, it is talking about functions that return a
sequence, or none (nil). It is the returned object that implements the
seq interface. If the function determines there are no items, no
sequence (nil) is returned, e.g. (concat "") -> nil

> Isn't this an empty
> sequence?

Since it is not an object, I would say nil is not a sequence. However,
the sequence interface functions (and many others) have well defined
values when passed nil. That doesn't make nil a sequence any more than
the fact that (assoc nil :fred :ethel) works makes nil a map.

Another way to look at it is that if you have a seq object (detectable
with if), it has a first value.

Yet another way to look at it is objects are not nil and vice versa.

If it's not confusing to you - great! But it seems many people, esp.
coming from Scheme, are having difficulty detaching the first/rest
protocol from Lisp's primordial data structure. Thus the (hopefully
clarifying :) dialogue.

Rich

MikeM

unread,
Jan 7, 2008, 9:42:27 PM1/7/08
to Clojure
Thanks, this dialogue is helpful.
Reply all
Reply to author
Forward
0 new messages