3

I've encountered a problem while I was doing a task from 4clojure.com. Here is the description of a task:

Write a function which returns the last element in a sequence.

I've solved it using the following code:

#(first (reverse %))

When I wanted to change the first function with a number of an index. like so:

#(0 (reverse %))

I've received an error:

java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.IFn

My question is: Why am I receiving this error? I cannot get it, because for instance ([1 2 3 4] 0) is perfectly valid and returns the first element of a sequence so why I cannot use index of an array in the function?

EDIT1: Even the following code does not work and I suppose APersistentVector is first there.

#((reverse %) 0)

EDIT2: I managed to make it work by converting the list which is returned from reverse function to vector. Thanks @Josh

(#((vec (reverse %)) 0)[1 2 3])

1 Answer 1

8

If you look at the code for APersistentVector, you will see:

public abstract class APersistentVector extends AFn ...

AFn implements IFn, which extends java's Callable and Runnable interfaces, which means that a clojure persistent vector can be called as a function, with the argument being used as the index to retrieve. You can see this here:

public Object invoke(Object arg1) {
    if(Util.isInteger(arg1))
        return nth(((Number) arg1).intValue());
    throw new IllegalArgumentException("Key must be integer");
}

The same is true for maps and sets; they can all be invoked as functions:

({:a 1 :b 2} :b)  ;; 2
(#{:a :b} :a)     ;; :a
([1 2 3 4] 0)     ;; 1

However, a Long (your number zero) does not implement IFn:

(ancestors (class 42))
=>
#{java.lang.Comparable
  java.lang.Number
  java.lang.Object
  java.io.Serializable}

Hence, it cannot be invoked as a function.

Sign up to request clarification or add additional context in comments.

5 Comments

But wait ([1 2 3 4] 0) works fine, so how it is possible that in this particular example it is invoked as a function?
@FieryCod Not sure I understand -- any clojure persistent vector that is the first element of a form (as in your example ([1 2 3 4] 0) ) will be invoked as a function, always. What do you mean, "this particular example"? first is a clojure core function, just to be clear.
By particular example I meant ([1 2 3 4] 0). Ok if you say that any persistent vector that is the first element of a form will be invoked as a function please enlighten me why this #(((reverse %) 0)) throws an error? If I understood you correctly it should work because PersistentVector is first.
You will notice that the error given when you try to apply that function to a sequence: ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.IFn. reverse does not return a vector; it returns a PersistentList, and lists do not implement IFn (one reason being that lists are not associative, i.e., they cannot be accessed via an index like vectors) @FieryCod
Thank you, you've perfectly explained it. Have a nice day:)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.