true?

16 views
Skip to first unread message

ntupel

unread,
Sep 30, 2008, 4:37:40 PM9/30/08
to Clojure
The following looks weird to me:

Clojure
user=> (.contains [1 2 3] 2)
true
user=> (true? (.contains [1 2 3] 2))
false

AFAICS true? is implemented using identical? which tests by reference
equality. Now since Java boolean values are boxed into Booleans we have
not only Boolean.TRUE. Maybe true? (and false?) should be implemented in
terms of equals?


Stuart Halloway

unread,
Sep 30, 2008, 5:29:05 PM9/30/08
to clo...@googlegroups.com
For your specific case you should probably be using contains?, which
works for both.

But I agree it seems odd.

Rich Hickey

unread,
Sep 30, 2008, 5:48:27 PM9/30/08
to Clojure


On Sep 30, 4:37 pm, ntupel <ntu...@googlemail.com> wrote:
> The following looks weird to me:
>
> Clojure
> user=> (.contains [1 2 3] 2)
> true
> user=> (true? (.contains [1 2 3] 2))
> false
>

Fixed - thanks for the report.

Rich

ntupel

unread,
Sep 30, 2008, 6:03:34 PM9/30/08
to clo...@googlegroups.com
On Tue, 2008-09-30 at 17:29 -0400, Stuart Halloway wrote:
> For your specific case you should probably be using contains?, which
> works for both.

No. contains? is meant for maps, i.e. when applied to vectors it checks
against indexes:

user=> (contains? [1 2 3] 0)
true


Stuart Halloway

unread,
Oct 3, 2008, 8:01:33 AM10/3/08
to clo...@googlegroups.com
I was surprised to find out that contains? checks keys, even on
vectors. Is this idiomatic in some language? I think most new users to
Clojure will find it confusing.

I propose that contains? checks values on vectors, leaving the
behavior as-is for other collection types.

And yes, I understand the existing behavior is consistent (at the data
structure level). But it doesn't meet user expectations.

Rich Hickey

unread,
Oct 3, 2008, 8:30:05 AM10/3/08
to Clojure


On Oct 3, 8:01 am, Stuart Halloway <stuart.hallo...@gmail.com> wrote:
> I was surprised to find out that contains? checks keys, even on
> vectors. Is this idiomatic in some language? I think most new users to
> Clojure will find it confusing.
>
> I propose that contains? checks values on vectors, leaving the
> behavior as-is for other collection types.
>
> And yes, I understand the existing behavior is consistent (at the data
> structure level). But it doesn't meet user expectations.
>

contains? is about associative things, and should remain so. It's a
powerful aspect of Clojure that you can take code that uses maps and
swap in vectors and vice-versa. Clojure is also generally careful not
to mix performance models, and contains? carries a better-than-linear
perf expectation. So, I'd prefer it not be semantically overloaded.

There have been requests for find in vector, and find in sequence,
which would be useful.

In particular, they are much more useful if they don't simply return a
boolean answer, which contains? does because the things it works on
are key based.

Possible models are CL's member, which works on lists and returns the
tail beginning with the found item, and position, which works on
sequences and returns the index if found. There are also versions of
each that use predicate functions.

http://www.lispworks.com/documentation/HyperSpec/Body/f_mem_m.htm
http://www.lispworks.com/documentation/HyperSpec/Body/f_pos_p.htm

I'm open to variants of either or both of these, and have left the
names open looking forward to supporting them eventually. My
inclination is that position in Clojure should work only on indexed
things - vectors and arrays.

Rich

Hans Hübner

unread,
Oct 3, 2008, 9:12:58 AM10/3/08
to Clojure
On 3 Okt., 08:30, Rich Hickey <richhic...@gmail.com> wrote:
> There have been requests for find in vector, and find in sequence,
> which would be useful.

In Common Lisp, it is often useful to consider lists or arrays being
sets and tewhether something is an element of it. In Clojure, one can
use the right data structures in the first place.

I think it is better not to let bad Common Lisp habits slip into
Clojure at this point. Rather let us CL people think some more :)

-Hans

Dimitre Liotev

unread,
Oct 3, 2008, 9:27:34 AM10/3/08
to clo...@googlegroups.com
Rich Hickey <richh...@gmail.com> writes:

[..]

> Possible models are CL's member, which works on lists and returns the
> tail beginning with the found item, and position, which works on
> sequences and returns the index if found. There are also versions of
> each that use predicate functions.
>
> http://www.lispworks.com/documentation/HyperSpec/Body/f_mem_m.htm
> http://www.lispworks.com/documentation/HyperSpec/Body/f_pos_p.htm
>
> I'm open to variants of either or both of these, and have left the

I'd like to have both. These are very useful functions and if their
addition wouldn't be in conflict with any other aspects of Clojure, then
why not include them?


--
Dimitre Liotev

Rich Hickey

unread,
Oct 3, 2008, 9:45:33 AM10/3/08
to Clojure


On Oct 3, 9:27 am, Dimitre Liotev <lio...@gmail.com> wrote:
The main reason, which I discussed with Hans on IRC, is that they have
bad performance characteristics. Lists and vectors make for bad sets,
and alists make for bad maps, with linear lookup times. Clojure has
real sets and maps, with reader and library support.

With those functions in place, people may come from CL and Scheme and
continue to use them where they are not appropriate; Clojure has
better, more scalable alternatives.

filter is already a lazy version of member-if, and automates the
pattern of searching again with the last found tail.

So maybe filter= would obviate the need for member, although there is
a very cool idiom for using sets as equality filters which works for
everything except nil and false:

(filter #{x} coll)

Which just leaves us without position/index-of

Rich

Paul Barry

unread,
Oct 3, 2008, 9:50:43 AM10/3/08
to Clojure
I agree with Stuart, I can't imagine this is how anyone new to Clojure
would expect this to work:

user=> (contains? [2 3 4] 1)
(contains? [2 3 4] 1)
true
user=> (contains? [2 3 4] 4)
(contains? [2 3 4] 4)
false
user=> (contains? (seq [2 3 4]) 1)
(contains? (seq [2 3 4]) 1)
false
user=> (contains? (seq [2 3 4]) 4)
(contains? (seq [2 3 4]) 4)
false

The fact that contains? is semantically different than
java.util.Collection#contains is confusing. If contains? was called
contains-key?, that would be more intuitive and map to how it works in
Java.

Stuart Halloway

unread,
Oct 3, 2008, 9:55:46 AM10/3/08
to clo...@googlegroups.com
Based on Rich's elaboration I would be satisified if contains? threw
an exception when called on a vector.

Rich Hickey

unread,
Oct 3, 2008, 10:14:20 AM10/3/08
to clo...@googlegroups.com
On Fri, Oct 3, 2008 at 9:55 AM, Stuart Halloway
<stuart....@gmail.com> wrote:
>
> Based on Rich's elaboration I would be satisified if contains? threw
> an exception when called on a vector.
>

I understand that it seems less useful for vectors than what you had
hoped it meant, but it is still a useful in-range test.

What if I were to add sparse vectors?

Rich

Stuart Halloway

unread,
Oct 3, 2008, 10:26:26 AM10/3/08
to clo...@googlegroups.com
> What if I were to add sparse vectors?

Continuing down the ugly path I started, those *wouldn't* throw an
exception. :-/

I am going to cease and desist now, and accept contains? as it is. But
somebody is going to need to write a book to explain these odd corners
to people coming from the Java world. Bwa ha ha ha ha. :-)

Stuart

Rich Hickey

unread,
Oct 3, 2008, 10:31:32 AM10/3/08
to Clojure
One thing I can certainly do is improve is the doc for contains?

Rich

Stephen C. Gilardi

unread,
Oct 3, 2008, 10:40:17 AM10/3/08
to clo...@googlegroups.com

On Oct 3, 2008, at 9:50 AM, Paul Barry wrote:

The fact that contains? is semantically different than
java.util.Collection#contains is confusing.  If contains? was called
contains-key?, that would be more intuitive and map to how it works in
Java.

Several times I've made the mental note: when I see contains? I need to think contains-key?. I think changing the name to contains-key? would make the meaning very clear.

Also, if you're dealing with values that are known not to be false or nil (which I suspect is a common case), (contains? m k) is equivalent to (m k). Typing the extra "-key?" seems worth it for its clarity in the "false or nil is possible" case.

--Steve

Allen Rohner

unread,
Oct 3, 2008, 10:48:19 AM10/3/08
to Clojure
> The main reason, which I discussed with Hans on IRC, is that they have
> bad performance characteristics. Lists and vectors make for bad sets,
> and alists make for bad maps, with linear lookup times. Clojure has
> real sets and maps, with reader and library support.

I ran into this problem last night actually, and maybe it could be
solved with education. :-) Is there a good way to convert an arbitrary
java.util.Collection into a clojure set?

I was working with some java code that returned a
java.util.Enumeration, and (set java-obj) was returning 'don't know
how to create ISeq from:'. If it were easier to convert java
collections into clojure, that would obviate at least some of my need
for a contains? on list/vectors/seqs.

The patch looks pretty easy. Rich, would you be amenable?

Allen

Rich Hickey

unread,
Oct 3, 2008, 11:57:36 AM10/3/08
to Clojure
It is not necessary. All Java collections can already be turned in to
sets using set:

(set (java.util.ArrayList. [1 2 3 4 5 3 2]))
#{1 2 3 4 5}

Enumerations are not collections, but can be turned into seqs
(manually only) using enumeration-seq.

Rich

Paul Barry

unread,
Oct 3, 2008, 12:15:55 PM10/3/08
to Clojure
On Oct 3, 10:26 am, Stuart Halloway <stuart.hallo...@gmail.com> wrote:
> But somebody is going to need to write a book to explain these odd corners  
> to people coming from the Java world. Bwa ha ha ha ha. :-)
>
> Stuart

Seriously, Clojure for Java Developers would be a great book. The
biggest topic that I think needs to be discussed is how you model
things in Clojure, considering Clojure and Java are so different.
Clojure is not object-oriented, you can't define classes, instead you
get data structures, metadata and multimethods. It's probably going
to be hard for many Java developers who have spent their entire career
learning object-oriented design principles to understand how to build
programs without using inheritance.

Rich Hickey

unread,
Oct 3, 2008, 1:42:59 PM10/3/08
to Clojure


On Oct 3, 10:40 am, "Stephen C. Gilardi" <squee...@mac.com> wrote:
> On Oct 3, 2008, at 9:50 AM, Paul Barry wrote:
>
> > The fact that contains? is semantically different than
> > java.util.Collection#contains is confusing. If contains? was called
> > contains-key?, that would be more intuitive and map to how it works in
> > Java.
>
> Several times I've made the mental note: when I see contains? I need
> to think contains-key?. I think changing the name to contains-key?
> would make the meaning very clear.
>

I'm not sure it's that clear cut. For instance, Clojure contains? maps
semantically and namewise to java.util.Set.contains, as it also works
for Clojure sets.

Collection.contains was always a bad idea, having indeterminate
performance.

> Also, if you're dealing with values that are known not to be false or
> nil (which I suspect is a common case), (contains? m k) is equivalent
> to (m k). Typing the extra "-key?" seems worth it for its clarity in
> the "false or nil is possible" case.
>

I don't think contains-key? works for sets or vectors very well, and
am not inclined to change this much-used name to this, since I'm
unlikely to want contains? for anything else, certainly not
questionable-performance generic collection value containment.

Rich

Allen Rohner

unread,
Oct 3, 2008, 2:17:30 PM10/3/08
to Clojure
> It is not necessary. All Java collections can already be turned in to
> sets using set:
>
> (set (java.util.ArrayList. [1 2 3 4 5 3 2]))
> #{1 2 3 4 5}
>
> Enumerations are not collections, but can be turned into seqs
> (manually only) using enumeration-seq.
>
> Rich

It's always great to see stuff already worked. Thanks!

Allen

Stuart Sierra

unread,
Oct 3, 2008, 6:56:06 PM10/3/08
to Clojure
On Oct 3, 8:01 am, Stuart Halloway <stuart.hallo...@gmail.com> wrote:
> I was surprised to find out that contains? checks keys, even on
> vectors. Is this idiomatic in some language? I think most new users to
> Clojure will find it confusing.

FYI, in clojure.contrib.seq-utils:

(defn includes?
"Returns true if s contains something equal (with =) to x."
[x s]
(if (some (fn [y] (= y x)) s)
true false))

Although I've found that whenever I use it, I'm better off using sets.

And I write "find" for vectors/sequences thus:
(first (filter #(some expression %) collection))

-Stuart
Reply all
Reply to author
Forward
0 new messages