Clojure

int coercion doesn't work in clojure 1.3

Details

  • Type: Defect Defect
  • Status: Closed Closed
  • Priority: Major Major
  • Resolution: Declined
  • Affects Version/s: Release 1.3
  • Fix Version/s: Release 1.5
  • Component/s: None
  • Labels:
    None
  • Environment:
    Gentoo GNU/Linux

Description

Using the clojure git head as of 2011-07-14 (commit f704853751d02faf72bd53be599ee0be6c1da63e), int coercion doesn't work:

user> (class (int 1))
java.lang.Long

byte, short, double, and float coercion work fine, though:

user> (class (byte 1))
java.lang.Byte
user> (class (short 1))
java.lang.Short
user> (class (double 1))
java.lang.Double
user> (class (float 1))
java.lang.Float

Also creating integers directly works fine:

user> (class (Integer. "100"))
java.lang.Integer
user> (class (Integer/valueOf 1))
java.lang.Integer
user> (class (Integer. 100))
java.lang.Integer

This is probably related to CLJ-439.

Activity

Hide
Michel Alexandre Salim added a comment -

This is fixed in 1.4.0 – could one of the screeners confirm this, and maybe close the issue?

Show
Michel Alexandre Salim added a comment - This is fixed in 1.4.0 – could one of the screeners confirm this, and maybe close the issue?
Hide
Tassilo Horn added a comment -

(int) (char) etc. are not intended to return boxed types, they always return primitive types.

Thank you, Sebastián, that made it clear and unveiled the problem at my side. When I did

(set-value! foo :position (int 17))

I got the exception "java.lang.Long cannot be cast to java.lang.Integer". set-value! is a protocol function extended on the java types of the java library I'm interacting with. Eventually, it'll call (doto foo (.setAttribute "position" (mutable <providedVal>)), where mutable is yet another protocol function that converts clojure collections to the libraries counterparts and does nothing for primitive types.

Now, although (int 17) returns an unboxed int, these two indirections box it into a Long again and the java setter is called with that leading to the error.

(set-value! foo :position (Integer/intValue 17))

circumvents the issue, because here you directly get an int boxed as Integer.

If you want boxed types you can use (num).

Well, I want a boxed value of a certain type, like Integer.

For short and byte, I don't know, I think there is a bug, (class (short 42)) should be Short.

Should or should not? Currently, for all primitive types <primType>, the call (class (<primType> <val>)) returns the wrapper class corresponding to <primType> with the exception of int where you get a Long instead of an Integer. That's totally surprising and caused me to file this bug report.

Show
Tassilo Horn added a comment - (int) (char) etc. are not intended to return boxed types, they always return primitive types. Thank you, Sebastián, that made it clear and unveiled the problem at my side. When I did (set-value! foo :position (int 17)) I got the exception "java.lang.Long cannot be cast to java.lang.Integer". set-value! is a protocol function extended on the java types of the java library I'm interacting with. Eventually, it'll call (doto foo (.setAttribute "position" (mutable <providedVal>)), where mutable is yet another protocol function that converts clojure collections to the libraries counterparts and does nothing for primitive types. Now, although (int 17) returns an unboxed int, these two indirections box it into a Long again and the java setter is called with that leading to the error. (set-value! foo :position (Integer/intValue 17)) circumvents the issue, because here you directly get an int boxed as Integer. If you want boxed types you can use (num). Well, I want a boxed value of a certain type, like Integer. For short and byte, I don't know, I think there is a bug, (class (short 42)) should be Short. Should or should not? Currently, for all primitive types <primType>, the call (class (<primType> <val>)) returns the wrapper class corresponding to <primType> with the exception of int where you get a Long instead of an Integer. That's totally surprising and caused me to file this bug report.
Hide
Sebastián Bernardo Galkin added a comment -

(int) (char) etc. are not intended to return boxed types, they always return primitive types. If you want boxed types you can use (num). When you do (class (int 42)) you are casting the long 42 to a int and then boxing it into a Long to get its class.

For short and byte, I don't know, I think there is a bug, (class (short 42)) should be Short.

Show
Sebastián Bernardo Galkin added a comment - (int) (char) etc. are not intended to return boxed types, they always return primitive types. If you want boxed types you can use (num). When you do (class (int 42)) you are casting the long 42 to a int and then boxing it into a Long to get its class. For short and byte, I don't know, I think there is a bug, (class (short 42)) should be Short.
Hide
Tassilo Horn added a comment -

But for what are the coercion functions now good for? I mean, http://clojure.org/java_interop#Java Interop-Coercions states:

"At times it is necessary to have a value of a particular primitive type. These coercion functions yield a value of the indicated type as long as such a coercion is possible: bigdec bigint boolean byte char double float int long num short"

That's exactly my use case which is not supported anymore.

Show
Tassilo Horn added a comment - But for what are the coercion functions now good for? I mean, http://clojure.org/java_interop#Java Interop-Coercions states: "At times it is necessary to have a value of a particular primitive type. These coercion functions yield a value of the indicated type as long as such a coercion is possible: bigdec bigint boolean byte char double float int long num short" That's exactly my use case which is not supported anymore.
Hide
Sebastián Bernardo Galkin added a comment -

Yes, I think so

Show
Sebastián Bernardo Galkin added a comment - Yes, I think so
Hide
Tassilo Horn added a comment -

So to call some Java method that requires an int you have to use Integer/valueOf?

Show
Tassilo Horn added a comment - So to call some Java method that requires an int you have to use Integer/valueOf?
Hide
Sebastián Bernardo Galkin added a comment -
Show
Sebastián Bernardo Galkin added a comment - See also this topic in clojure-dev: https://groups.google.com/d/topic/clojure-dev/fXQAYv8s0tQ/discussion
Hide
Sebastián Bernardo Galkin added a comment -

Related documentation here: http://dev.clojure.org/display/doc/Enhanced+Primitive+Support

all long-or-smaller integers are boxed as Long
You can't use primitive coercions to force specific box types
Your code was broken if you were relying on that

So, apparently (int) has the correct behavior. It's byte and short which should be also boxed into Longs

Show
Sebastián Bernardo Galkin added a comment - Related documentation here: http://dev.clojure.org/display/doc/Enhanced+Primitive+Support all long-or-smaller integers are boxed as Long You can't use primitive coercions to force specific box types Your code was broken if you were relying on that So, apparently (int) has the correct behavior. It's byte and short which should be also boxed into Longs

People

Vote (0)
Watch (3)

Dates

  • Created:
    Updated:
    Resolved: