Tassilo Horn <tass...@member.fsf.org> writes:

Hi again,

> Now I've spotted the problem, although I don't know how to fix it yet.
> The problem is that my implementation doesn't work with LazySeqs.  A
> minimal example at the REPL is that:
>
> funql.test.core> (into (ordered-set) (take 10 (iterate inc 0)))
> #{}
>
> Here, I want to put the first 10 natural numbers into the empty ordered
> set, but the result is empty.

My observation was false.  The problem is not the the second parameter,
but the first one.  If the PersistentOrderedSet given to `into' is
empty, then the transient version fails:

  funql.core> (into (ordered-set) [1 2 3])
  #{}

Or doing what `into' does manually:

  funql.core> (persistent! (conj! (transient (ordered-set)) 1))
  #{}

Of course, the non-transient variant works as expected:

  funql.core> (conj (ordered-set) 1)
  #{1}

Then I added some debug code to my TransientOrderedSet.conj() method:

--8<---------------cut here---------------start------------->8---
static final class TransientOrderedSet 
extends AFn implements ITransientSet {
    ITransientSet items;
    ITransientVector order;

    @Override
    public ITransientSet conj(Object obj) {
      if (items.contains(obj)) {
        System.out.println(obj  // #### DEBUGGING OUTPUT ####
            + " is already contained in the ordered set of "
            + items.count() + " items, doing nothing!");
        return this;
      }
      ITransientSet s = (ITransientSet) items.conj(obj);
      if (s != items) {
        items = s;
      }
      ITransientVector v = (ITransientVector) order.conj(obj);
      if (v != order) {
        order = v;
      }
      return this;
    }
}
--8<---------------cut here---------------end--------------->8---

With the debugging version in the REPL, the call

  (persistent! (conj! (transient (ordered-set)) 1))

prints

  1 is already contained in the ordered set of 0 items, doing nothing!

How can it be that an empty ITransientSet (which is really a
TransientHashSet) contains 1?  (In fact, you can try to conjoin
arbitrary elements, it'll always state that the element is already
contained).

Contrarily, when conjoining into a TransientOrderedSet that was created
for an PersistentOrderedSet that was in turn created with a non-empty
constructor, it works as expected:

  funql.core> (persistent! (conj! (transient (ordered-set 0)) 1))
  #{0 1}

I now have fixed it by implementing contains() as follows and using that
throughout my class instead of only invoking the contains() on the
TransientHashSet backing the TransientOrderedSet...

    public boolean contains(Object obj) {
      // FIXME: This is a workaround for the puzzling fact that
      // PersistentHashSet.EMPTY.asTransient().contains(o) for any Object
      // o.
      return (items.count() != 0) && items.contains(obj);
    }

I will open a separate thread on this exact issue.

Bye,
Tassilo

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to