bug in 'extend-protocol' ???

93 views
Skip to first unread message

Jim - FooBar();

unread,
Jun 13, 2013, 11:28:48 AM6/13/13
to clo...@googlegroups.com
Hi all,

can anyone explain why these 2 are different given the same protocol
(the only difference is the swapped ordering)?

(defprotocol FOO
(bar [this a]
[this a b]) )

(extend-protocol FOO ;;THIS WORKS
(Class/forName "[D")
(bar
([_ a] a)
([_ a b] (+ a b)))
String
(bar
([_ a] (str a))
([_ a b] (str a b))))


(extend-protocol FOO ;;THIS WON'T COMPILE
String
(bar
([_ a] (str a))
([_ a b] (str a b)))
(Class/forName "[D")
(bar
([_ a] a)
([_ a b] (+ a b))) )

CompilerException java.lang.UnsupportedOperationException: nth not
supported on this type: Character, compiling:(NO_SOURCE_PATH:1:1)

it seems that the extension points include arrays, the ordering
matters!!! The extension to array has to come first otherwise it won't
even compile...Moreover, and possibly for the same reason, multiple
extensions for different array-types fails with the same exception. for
example while the following works:

(extend-protocol FOO
(Class/forName "[D")
(bar
([_ a] a)
([_ a b] (+ a b))) )

trying to add more types fails:

(extend-protocol FOO
(Class/forName "[D")
(bar
([_ a] a)
([_ a b] (+ a b)))
(Class/forName "[F")
(bar
([_ a] a)
([_ a b] (+ a b))) )

CompilerException java.lang.UnsupportedOperationException: nth not
supported on this type: Character, compiling:(NO_SOURCE_PATH:1:1)

Jim

Marshall Bockrath-Vandegrift

unread,
Jun 13, 2013, 1:16:16 PM6/13/13
to clo...@googlegroups.com
"Jim - FooBar();" <jimpi...@gmail.com> writes:

> CompilerException java.lang.UnsupportedOperationException: nth not
> supported on this type: Character, compiling:(NO_SOURCE_PATH:1:1)

If you examine the implementation of `extend-protocol` and for how it
distinguishes between additional functions being defined for a type and
new types to which to extend the protocol, I think you’ll see what’s
going on here.

-Marshall

Leon Barrett

unread,
Jun 13, 2013, 1:28:48 PM6/13/13
to clo...@googlegroups.com
It shouldn't be necessary to examine the source to know what's going on in a builtin, really, but I also encountered this one recently. The way the extend-protocol macro finds which entries are types and which are function definitions is by checking which are lists.

Frankly, a better macro would involve a vector, e.g.

(extend-protocol FOO
  [(Class/forName "[D")
   (methods...)]
  [otherClass
    (methods...)])

Jim - FooBar();

unread,
Jun 13, 2013, 1:41:16 PM6/13/13
to clo...@googlegroups.com
On 13/06/13 18:16, Marshall Bockrath-Vandegrift wrote:
> "Jim - FooBar();" <jimpi...@gmail.com> writes:
>
>> CompilerException java.lang.UnsupportedOperationException: nth not
>> supported on this type: Character, compiling:(NO_SOURCE_PATH:1:1)
> If you examine the implementation of `extend-protocol` and for how it
> distinguishes between additional functions being defined for a type and
> new types to which to extend the protocol, I think you�ll see what�s
> going on here.
>
> -Marshall
>


'extend-protocol' simply expands to a bunch of 'extend-type' forms. In
my example I used 'extend-protocol' and then 'extend-type' on a type not
included in the extend-protocol form. I did that only because I get a
compilation error when I try to provide extension points for both
'doubles' and 'floats'. That led me to pull out the code-block for
'floats' and use extend-type specifically for floats. That compiled, but
because it's using amap internally, throws the exception I mentioned
previously. The exception you've responded to is only thrown when I try
to put both extension points in the same 'extend-protocol' form or in
fact, whenever any extension for primitive arrays doesn't come first
before everything else! are the 2 problems related? where should I look
for the one error and where for the other?

thanks,

Jim

Jim - FooBar();

unread,
Jun 13, 2013, 1:47:10 PM6/13/13
to clo...@googlegroups.com
On 13/06/13 18:28, Leon Barrett wrote:
> It shouldn't be necessary to examine the source to know what's going
> on in a builtin, really, but I also encountered this one recently. The
> way the extend-protocol macro finds which entries are types and which
> are function definitions is by checking which are lists.

I'm not sure I follow...if we can't have lists that evaluate to Class
objects then how am I able to succesfully use (Class/forName "[D") as
the first extension but not in any other position?
should I be using (eval (Class/forName "[D")) so the macro definitely
receives a Class?

You say you've encountered this a lot...can you elaborate? what did you do?

many many thanks,

Jim




Jim - FooBar();

unread,
Jun 13, 2013, 1:52:59 PM6/13/13
to clo...@googlegroups.com
or can you perhaps show an example of successfully extending any
protocol to at least 2 primitive array types?

Jim

Jim - FooBar();

unread,
Jun 13, 2013, 1:59:14 PM6/13/13
to clo...@googlegroups.com
If I simply def the class objects upfront and use the vars in the
extend-protocol macro?that could possibly work as there will be no
confusion as to what is a list and what isn't... I'll try that as soon
as I get back!

Jim

Aaron Cohen

unread,
Jun 13, 2013, 2:02:52 PM6/13/13
to clo...@googlegroups.com
On Thu, Jun 13, 2013 at 1:52 PM, Jim - FooBar(); <jimpi...@gmail.com> wrote:
or can you perhaps show an example of successfully extending any protocol to at least 2 primitive array types?

You can call extend-protocol several times:

user=> (defprotocol A (foo [a b]))
A
user=> (extend-protocol A (Class/forName "[D") (foo [a b] [a b]))
nil
user=> (extend-protocol A (Class/forName "[F") (foo [a b] [a b]))
nil
user=> (foo (double-array [1 2 3]) 1)
[#<double[] [D@5a12d46c> 1]
user=> (foo (float-array [1 2 3]) 1)
[#<float[] [F@5e310a07> 1]


Leon Barrett

unread,
Jun 13, 2013, 2:14:41 PM6/13/13
to clo...@googlegroups.com
On Thu, Jun 13, 2013 at 10:52 AM, Jim - FooBar(); <jimpi...@gmail.com> wrote:
On 13/06/13 18:47, Jim - FooBar(); wrote:
On 13/06/13 18:28, Leon Barrett wrote:
It shouldn't be necessary to examine the source to know what's going on in a builtin, really, but I also encountered this one recently. The way the extend-protocol macro finds which entries are types and which are function definitions is by checking which are lists.

I'm not sure I follow...if we can't have lists that evaluate to Class objects  then how am I able to succesfully use (Class/forName "[D") as the first extension but not in any other position?
should I be using (eval (Class/forName "[D")) so the macro definitely receives a Class?

You say you've encountered this a lot...can you elaborate? what did you do?

If you want to understand why it behaves the way it does, then I do encourage you to read the source(clj/clojure/core_deftype.clj). Basically, it knows the first thing is a type and then uses (take-while seq?) to find that type's methods.

extend-protocol is a macro that expands to a bunch of extend-type calls. Just make a bunch of extend-type calls, or make your own macro that makes a bunch of extend-type calls.


many many thanks,

Jim





or can you perhaps show an example of successfully extending any protocol to at least 2 primitive array types?


Jim

--
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+unsubscribe@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- You received this message because you are subscribed to a topic in the Google Groups "Clojure" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojure/0TJ-Kl3CsDk/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clojure+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



Jim - FooBar();

unread,
Jun 13, 2013, 4:03:54 PM6/13/13
to clo...@googlegroups.com
I wish I could...if I do that I can't call amap on any other primitive array but the first extended - I get the exception I posted earlier and it has nothing to do with type hinting the array. I'm type-hinting it in both cases:

IllegalArgumentException No matching method found: aset  clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:80)

ok it's starting t get annoying so let's work with a concrete example:


(defprotocol FOO
 (bar [this a] [this a b]))

(extend-protocol FOO  
(Class/forName "[D") 
(bar
([this a]
   (amap ^doubles this idx ret (a (aget ^doubles this idx) 10.0)))
([this a b]
   (bar this #(apply a %1 (list %2 b))))) )

user=> (bar (double-array 1) +)
#<double[] [D@6239ae30>
user=> (seq *1)
(10.0)

Right, all is well! let's carry on...I'm going to copy-paste the code-block above only changing the 'doubles'->floats

(extend-protocol FOO  
(Class/forName "[F") 
(bar
([this a]
   (amap ^floats this idx ret (a (aget ^floats this idx) (float 10))))
([this a b]
   (bar this #(apply a %1 (list %2 b))))) )

user=> (bar (float-array 1) +)

IllegalArgumentException No matching method found: aset  clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:80)

any other type I try from now onwards will fail with the same exception. Could it be because Clojure changes the types internally to longs?
I don't understand!forgive me but I'm a bit annoyed with this...

Jim
--
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to

For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.

Jim - FooBar();

unread,
Jun 13, 2013, 4:14:05 PM6/13/13
to clo...@googlegroups.com
an epiphany finally!!!

while writing my response previously I realised that adding 2 numbers of different type usuallly returns either a double or a long. That was the source of confusion... I need to coerce whatever number my fn is returning to the type the array is expecting (duh!)

I feel properly stupid now!

thanks all of you who bothered responding...

Jim
Reply all
Reply to author
Forward
0 new messages