Search code examples
clojuredestructuring

Destructuring a function in a list


I have the following two test cases in Clojure, one destructuring a vector, and one destructuring a list:

user=>  ((fn [[a op b]] (op a b)) [1 + 2])
3
user=>  ((fn [[a op b]] (op a b)) '(1 + 2))
2

Why is the symbol + evaluated in the first test case but not the second? Is the quote recursive, so in the second test case op is really 'op?


Solution

  • You are correct that the single quote ' (equivalent of the function quote) will return a list of symbols, suppressing evaluation. However, since symbols cannot start with a number, the PersistentList '(1 + 2) will contain a java.lang.Long, a clojure.lang.Symbol, and a java.lang.Long.

    When you invoke the function given by the Symbol + (which is possible because Symbol extends AFn which itself implements IFn, and overrides the invoke function), this gets executed:

    public Object invoke(Object obj, Object notFound) {
        return RT.get(obj, this, notFound);
    }
    

    Since you executed (op a b), or ('+ 1 2), obj is 1, notFound is 2, and this is the Symbol + in the call to clojure.lang.RT's get method, which looks like this:

    static public Object get(Object coll, Object key, Object notFound){
        if(coll instanceof ILookup)
            return ((ILookup) coll).valAt(key, notFound);
        return getFrom(coll, key, notFound);
    }
    

    Again, coll is the Long 1, key is the Symbol +, and notFound is the Long 2.

    So when a function is called, it's being looked up in a collection. Since 1 is not a collection, the value notFound, or 2, is being returned.

    As a visual of a ('+ 5 10) example, in a debugger:

    Symbol in debugger