extend-type and extend-protocol: different syntax for multi-arity methods

687 views
Skip to first unread message

Alexey Cherkaev

unread,
May 13, 2015, 8:05:24 AM5/13/15
to clo...@googlegroups.com

Hi all,

If you have a protocol

(defprotocol Foo (foo [x] [x y]))

and implement it for the record

(defrecord Bar [p q r]
  Foo
  (foo [x] x)
  (foo [x y] [x y]))

you write each method separately. The same is true for extend-type. Yet, if you use extend-protocol syntax is more like usual Clojure multi-arity function definition:

(extend-protocol Foo
  Bar
  (foo
     ([x] x)
     ([x y] [x y])))

The first question is why there is a difference?

Secondly, if you mess up which syntax is where, the error you will get is quite obscure, nothing guards you against essentially a wrong syntax: both extend-type and extend-protocol are macros, so it shouldn’t be too difficult to add a quick check on correctness.

But lastly, wouldn’t it be better to have a uniform syntax?

Regards,
Alexey


Tassilo Horn

unread,
May 13, 2015, 8:46:33 AM5/13/15
to Alexey Cherkaev, clo...@googlegroups.com
Alexey Cherkaev <alexey....@gmail.com> writes:

Hi Alexey,

> If you have a protocol
>
> (defprotocol Foo (foo [x] [x y]))
>
> and implement it for the record
>
> (defrecord Bar [p q r]
> Foo
> (foo [x] x)
> (foo [x y] [x y]))
>
> you write each method separately. The same is true for extend-type.
> Yet, if you use extend-protocol syntax is more like usual Clojure
> multi-arity function definition:
>
> (extend-protocol Foo
> Bar
> (foo
> ([x] x)
> ([x y] [x y])))
>
> The first question is why there is a difference?

I think, the difference is that deftype/defrecord create an interface
(and an implementation class) under the hoods, and there, the different
arities of foo are actually different methods.

extend/extend-type/extend-protocol dynamically extend a protocol to some
type. Basically, the protocol's underlying dynamic dispatch table gets
a new [type impl-function] entry where impl-function is a real Clojure
function, thus you must specify all arities you want to support the
normal Clojure way.

> Secondly, if you mess up which syntax is where, the error you will get
> is quite obscure, nothing guards you against essentially a *wrong
> syntax*: both extend-type and extend-protocol are macros, so it
> shouldn’t be too difficult to add a quick check on correctness.

Yeah, for extend-protocol/extend-type the standard multi-arity syntax is
the only correct one.

> But lastly, wouldn’t it be better to have a uniform syntax?

The problem is that defrecord and deftype also allow for implementing
interfaces. If Foo above was an interface, foo with 1 argument and foo
with 2 arguments are completely separate methods (ok, they overload),
thus it makes sense to define them separately. However, if Foo was a
protocol, it would also make sense to notate it as multi-arity function.
But then you have an inconsistent syntax inside defrecord/deftype.
Well, although one could argue that this was a good thing because it
would allow to see immediately if Foo was a protocol or an interface.

Bye,
Tassilo

Alexey Cherkaev

unread,
May 14, 2015, 3:01:09 AM5/14/15
to Alexey Cherkaev, clo...@googlegroups.com

Hi Tassilo,

Thanks for the reply.

The thing is, although the implementations for extending protocols directly in records and with extend-type might be different, there is no reason why the syntax should be different: from Clojure-programmer perspective it’s all the same. It is a leaked abstraction if we have to thing about those details. The same applies for interface implementation: overloaded methods there and multi-arity functions in Clojure shouldn’t look differently to a Clojure programmer (unless there is some more profound difference).



Best regards,
Alexey
Reply all
Reply to author
Forward
0 new messages