beluchin
beluchin

Reputation: 12682

how to combine protocol function with function with same name and different arity?

I have a function foo that takes a single argument whose implementation depends on the type of the argument, hence a protocol:

(defprotocol Foo
  (foo [x]))

On the same namespace, I also would like a function with the same name (foo) that takes variable arguments and that calls for each argument the single-arg foo. Something like:

(defn foo [x1 x2 & more]
  (doseq [x (concat [x1 x2] more)])
    (foo x))))

How to implement that?

Upvotes: 1

Views: 286

Answers (2)

nberger
nberger

Reputation: 3659

Just adding to Tim Pote's answer, let me quote an answer from Stuart Halloway:

[...] protocols are the contract for implementers, not the contract for callers. If you change a contract for implementers, then the implementers must change.

[...] a function that has a reasonable default for any object. Often such a function does not need to be part of the contract for implementers (i.e. the protocol) at all.

It's liberating for the protocol implementers, because you can set default values or add support to multiple arities (like in your case) in the public api fn, without having to worry about all of that in the concrete implementations.

Upvotes: 3

Tim Pote
Tim Pote

Reputation: 28019

With the defprotocol you've declared the function foo. Later calling (defn foo ...) effectively overwrites your previous declaration.

One common idiom is to prepend a - to your protocol fn (i.e. -foo). This is basically Hungarian Notation for "This is an internal protocol function. There is a wrapper for it in this namespace. You should call that instead." This leaves the protocol open for extension, but allows you to wrap the invocation.

Another thing I would consider in your case is whether or not the name foo is appropriate for your wrapper. The fact that it operates on multiple Foos indicates that maybe something like do-foos is more appropriate.

Upvotes: 2

Related Questions