[PATCH] defprotocol now warns when it overwrites an exising method var

134 views
Skip to first unread message

Chouser

unread,
Nov 12, 2009, 10:27:00 PM11/12/09
to cloju...@googlegroups.com
With this patch:

user=> (defprotocol Bar (foo [i]))
Bar
user=> (defn bar [])
#'user/bar
user=> (defprotocol Foo (foo [i] "docs") (bar [i]))
Warning: protocol #'user/Foo is overwriting method foo of protocol Bar
Warning: protocol #'user/Foo is overwriting function bar
Foo
defprotocol-warn.diff

Laurent PETIT

unread,
Nov 13, 2009, 1:26:41 AM11/13/09
to cloju...@googlegroups.com
Cool!

Would it be interesting to fully qualify the vars with their
namespaces in the message ?

user=> (defprotocol Foo (foo [i] "docs") (bar [i]))
Warning: protocol #'user/Foo is overwriting method foo of protocol #'user/Bar
Warning: protocol #'user/Foo is overwriting function user/bar

Which brings another question to the table: how does 'use write with
protocols, when in a ns A I want to use protocol defined in a ns B ?

user=> (ns 'A)
A=> (defn b [])
; assume ns B defined a protocol ProtB
A=> ('use ????) ; how to "import the protocol ProtB" / "make its
methods available from ns A" ?

I guess in projects of a certain size, one would want to have some
"initialization part" of the code 'require the protocol definition
itself, as well as 'require the needed implementations of the
protocol. And, in the "application part", just 'require/refer to the
protocol without having to deal with the implementations.

How far from reality am I in my understanding ?

2009/11/13 Chouser <cho...@gmail.com>:
> --
>
> You received this message because you are subscribed to the Google Groups "Clojure Dev" group.
> To post to this group, send email to cloju...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/clojure-dev?hl=.
>
>
>

Konrad Hinsen

unread,
Nov 13, 2009, 3:44:57 AM11/13/09
to cloju...@googlegroups.com
On 13 Nov 2009, at 07:26, Laurent PETIT wrote:

> Which brings another question to the table: how does 'use write with
> protocols, when in a ns A I want to use protocol defined in a ns B ?
>
> user=> (ns 'A)
> A=> (defn b [])
> ; assume ns B defined a protocol ProtB
> A=> ('use ????) ; how to "import the protocol ProtB" / "make its
> methods available from ns A" ?

At the moment, one by one as if they were ordinary functions or
multimethods.

I agree that it would be nice to be able to treat protocols as a
package and refer to methods through the protocol object itself, e.g.:

(ns A)
(defprotocol Bar (foo [i]))

(ns B
(:use [A :only (Bar)]))

; assume x refers to an object that implements Bar:
((Bar/foo) x)


That would also permit to use the same method name in several
protocols in the same namespace - but then Chouser's patch could
quickly become undesirable.

Konrad.

Laurent PETIT

unread,
Nov 13, 2009, 5:47:39 AM11/13/09
to cloju...@googlegroups.com
2009/11/13 Konrad Hinsen <konrad...@fastmail.net>:
> On 13 Nov 2009, at 07:26, Laurent PETIT wrote:
>
>> Which brings another question to the table: how does 'use write with
>> protocols, when in a ns A I want to use protocol defined in a ns B ?
>>
>> user=> (ns 'A)
>> A=> (defn b [])
>> ; assume ns B defined a protocol ProtB
>> A=> ('use ????) ; how to "import the protocol ProtB" / "make its
>> methods available from ns A" ?
>
> At the moment, one by one as if they were ordinary functions or
> multimethods.
>
> I agree that it would be nice to be able to treat protocols as a
> package and refer to methods through the protocol object itself, e.g.:
>
> (ns A)
> (defprotocol Bar (foo [i]))
>
> (ns B
>   (:use [A :only (Bar)]))

Since the strong point of Protocols is to group related functions
together, I guess that it may not only be desirable, but also
required, if we don't want such situations to arise:

(ns A)
(defprotocol Bar (foo [i]) (bar [j]))

(ns B
(:use [A :only [foo])) ; oops I made an error, maybe bar was added
to Bar later on ...
(defn bar [j])


>
> ; assume x refers to an object that implements Bar:
> ((Bar/foo) x)

Just to be sure, shouldn't it be written
(Bar/foo x) instead of ((Bar/foo) x) ?

But I'm not sure requiring to write Bar/foo is good or not. My point
was not referring to this, but rather to import all protocol functions
as a whole, not piece by piece.

>
>
> That would also permit to use the same method name in several
> protocols in the same namespace - but then Chouser's patch could
> quickly become undesirable.
>
> Konrad.
>

Konrad Hinsen

unread,
Nov 13, 2009, 5:57:24 AM11/13/09
to cloju...@googlegroups.com
On 13.11.2009, at 11:47, Laurent PETIT wrote:

>> ; assume x refers to an object that implements Bar:
>> ((Bar/foo) x)
>
> Just to be sure, shouldn't it be written
> (Bar/foo x) instead of ((Bar/foo) x) ?

Yes, that's what I intended, but it's an imaginary syntax anyway for
the moment. I am not even sure that the slash syntax is the best
choice. With current Clojure syntax rules, it would imply that
protocols are implemented as a class of which the methods are static
members. Perhaps a keyword-based access would be more consistent,
considering how extend works.

> But I'm not sure requiring to write Bar/foo is good or not. My point
> was not referring to this, but rather to import all protocol functions
> as a whole, not piece by piece.

I see only two possibilities for importing a protocol as a unit:

1) Making the namespace functions aware of protocols and have it
handle protocol-defined functions specially.

2) Importing just the protocol object and accessing the functions
through it.

I don't like 1) because it complicates namespaces with special cases.
That's why I mentioned 2).

Konrad.

Chouser

unread,
Nov 13, 2009, 8:38:49 AM11/13/09
to cloju...@googlegroups.com
On Fri, Nov 13, 2009 at 1:26 AM, Laurent PETIT <lauren...@gmail.com> wrote:
>
> Would it be interesting to fully qualify the vars with their
> namespaces in the message ?
>
> user=> (defprotocol Foo (foo [i] "docs") (bar [i]))
> Warning: protocol #'user/Foo is overwriting method foo of protocol #'user/Bar
> Warning: protocol #'user/Foo is overwriting function user/bar

You will only get this message when both (or all three) of the
mentioned things are in the same namespace. I included the
namespace on the first protocol to make it clear the source of
the problem, but then don't repeat that same namespace on the
rest for brevity.

--Chouser

Chouser

unread,
Nov 13, 2009, 11:13:12 AM11/13/09
to cloju...@googlegroups.com
On Fri, Nov 13, 2009 at 5:47 AM, Laurent PETIT <lauren...@gmail.com> wrote:
>
> Since the strong point of Protocols is to group related functions
> together, I guess that it may not only be desirable, but also
> required, if we don't want such situations to arise:
>
> (ns A)
> (defprotocol Bar (foo [i]) (bar [j]))
>
> (ns B
>  (:use [A :only [foo])) ; oops I made an error, maybe bar was added
> to Bar later on ...
> (defn bar [j])

This is actually a desirable outcome, isn't it? If A added bar
later but you don't need it in B, you're perfectly fine defining
your own B/bar. If all of Bar's methods were brought into
B without naming them explicitly, then the addition of A/bar
could cause you problems in B.

>> ; assume x refers to an object that implements Bar:
>> ((Bar/foo) x)
>
> Just to be sure, shouldn't it be written
> (Bar/foo x) instead of ((Bar/foo) x) ?

That of course looks like namespace resolution when it isn't.
For the sake of discussion, let's use (Bar:foo x) instead, to
indicate Bar is a protocol. In fact, since Bar is itself inside
the A namespace, we could say (A/Bar:foo x). But of course this
is exactly the same as saying (A/foo x) as we can do today. Is
a new, longer way to resolve a function name actually desirable?

--Chouser

Laurent PETIT

unread,
Nov 13, 2009, 11:48:33 AM11/13/09
to cloju...@googlegroups.com
I don't have the answer to your questions, so I guess I once more
succombed to my "too much in advance anticipation of potential
problems" mental bias :-)

2009/11/13 Chouser <cho...@gmail.com>:
Reply all
Reply to author
Forward
0 new messages