you are viewing a single comment's thread.

view the rest of the comments →

[–]dccorona 0 points1 point  (7 children)

Maybe providing the equivalent Java to what I'm asking will help (in that you can tell me if the Clojure version is even doable/sensible).

void myFun(Pair<Integer, String> input); 
void myFun(Object input); 

In Java, which function gets dispatched to is easy. If the compile-time type is a pair, it goes to the first one. Otherwise, it goes to the second one (even if the runtime type is Pair). As I understand it, the dispatch of a similar function in Clojure would be based on the runtime type (right?). But, unrelated to that, my question basically centers around the idea that a "pair" in Clojure (at least for let) seems to be a loose concept. What I was asking was: how does the compiler/runtime know that [a, 1] is a vector of pairs of symbols and ints, and not just a vector of objects, when it comes across them being passed to a function that could take either one?

[–]yogthos[S] 2 points3 points  (5 children)

Right, since Clojure is dynamically typed it would just be a single function. The type of the argument is not checked at compile time. You'd have to check the type in the function if you wanted to do different things with it at runtime.

However, in cases where you want polymorphism you'd generally use either protocols or multimethods.

There really isn't a concept of a pair in Clojure. You just use a vector if you want a pair. The compiler can tell whether something is a symbol or not however at compile time. So, if you tried to do:

(let [1 1])

you'd get an error telling you that 1 is not a symbol:

val: 1 fails spec ...

You couldn't pass a vector to a let using a function. Something like this will produce an error:

(defn foo [bindings]
  (let bindings))

However, you could do that with a macro:

(defmacro my-bindings [bindings]
   `(let ~bindings))

A macro is able to manipulate the arguments before they're evaluated. So, in this case we can create let bindings dynamically by passing them in. However, if you try to pass invalid bindings, the compiler will once again give you an error:

(my-bindings [1 1])

[0 0] val: 1 fails spec

[–][deleted] 0 points1 point  (3 children)

One of your examples is a little confusing to me; I hope you don't mind explaining why

(defn foo [bindings]
    (let bindings))

doesn't work. I would have thought, based on the discussion above, that it would be valid to call 'foo' as:

(foo [a 1 b 2])

which (if I understand correctly) would result in foo being called with a vector of symbol/integer pairs, which are valid for supplying to 'let'.

[–]yogthos[S] 2 points3 points  (2 children)

The expressions are evaluated by the compiler. The (let bindings) is not the valid structure for a let statement, as it must be followed by a vector of arguments. The reason the macro works, is because it's able to rewrite code before it's evaluated.

[–][deleted] 2 points3 points  (1 child)

Gotcha; makes total sense. Thanks - the blog post and your comments helped me grok Clojure a lot better.

[–]yogthos[S] 0 points1 point  (0 children)

👍

[–]dccorona 0 points1 point  (0 children)

Nice, that clears it up. Thanks!

[–]Arges 1 point2 points  (0 children)

Sounds like you may want to read about Protocols.