Clojure

Implicit casting behaviour of into-array differs from <primitive>-array

Details

  • Type: Defect Defect
  • Status: Closed Closed
  • Priority: Minor Minor
  • Resolution: Completed
  • Affects Version/s: Release 1.3
  • Fix Version/s: Release 1.6
  • Component/s: None
  • Labels:
    None
  • Patch:
    Code and Test
  • Approval:
    Ok

Description

The behavior of byte-array and short-array is inconsistent with the other <type>-array functions and with the into-array function when invoked with types other than byte or short. All of the other cases upcast to Number, then extract the primitive value, allowing this operation to succeed (assuming the value is in range). byte-array and short-array throw a ClassCastException.

Example:

base64v3a=> (into-array Byte/TYPE [1 2 3 4])  ;; int to byte ok
#<byte[] [B@5ee04fd>
base64v3a=> (byte-array [1 2 3 4])  ;; int to byte NOT ok!! 
ClassCastException java.lang.Long cannot be cast to java.lang.Byte
  clojure.lang.Numbers.byte_array (Numbers.java:1418)
base64v3a=> (long-array [1 2 3 4])  ;; int to long ok
#<long[] [J@3f9f4d1d>

into-array (via RT.seqToTypedArray) and the other <type>-array functions all upcast to Number via Numbers.<type>_array), then obtain the proper primitive value. Numbers.byte-array and Numbers.short-array do casts directly to Byte and Short (yielding the ClassCastException).

The attached patch makes the Byte and Short cases match the other types and the into-array behavior. Tests are included. The submitter is a contributor.

Patch: clj766-2.patch

Screened by: Alex Miller

Activity

Hide
Alexander Taggart added a comment -

See CLJ-678.

Show
Alexander Taggart added a comment - See CLJ-678.
Alexander Taggart made changes -
Field Original Value New Value
Attachment clj766.patch [ 10174 ]
Alexander Taggart made changes -
Attachment clj766.patch [ 10174 ]
Hide
Andy Fingerhut added a comment -

Some more details from Alexandar Taggart: This is not a duplicate of CLJ-678. CLJ-766 was created precisely due to the fact the the behavior of *-array is not consistent with the post-678 version of into-array.

Show
Andy Fingerhut added a comment - Some more details from Alexandar Taggart: This is not a duplicate of CLJ-678. CLJ-766 was created precisely due to the fact the the behavior of *-array is not consistent with the post-678 version of into-array.
Hide
Karsten Schmidt added a comment -

I'd like to bump up this issue, since it'd be great if all the (xxx-array) factory functions have the same expected behavior (i.e. not throw an exception, especially not if the values are in range). The attached patch is changing the behaviour for byte-array & short-array to the same pattern used as for int/long/float/double and therefore will not throw an exception for valid (even if overflown) numbers. You can find more discussion in this thread on:

https://groups.google.com/forum/?hl=en&fromgroups=#!topic/clojure/KyQrbph-zqo

Show
Karsten Schmidt added a comment - I'd like to bump up this issue, since it'd be great if all the (xxx-array) factory functions have the same expected behavior (i.e. not throw an exception, especially not if the values are in range). The attached patch is changing the behaviour for byte-array & short-array to the same pattern used as for int/long/float/double and therefore will not throw an exception for valid (even if overflown) numbers. You can find more discussion in this thread on: https://groups.google.com/forum/?hl=en&fromgroups=#!topic/clojure/KyQrbph-zqo
Karsten Schmidt made changes -
Attachment byte-short-array-ctors.diff [ 11887 ]
Hide
Andy Fingerhut added a comment -

Voting on a ticket (click the "Vote" link under the "People" heading while viewing the ticket on JIRA) may help draw attention to it, too.

Show
Andy Fingerhut added a comment - Voting on a ticket (click the "Vote" link under the "People" heading while viewing the ticket on JIRA) may help draw attention to it, too.
Hide
Andy Fingerhut added a comment -

Karsten, patches should be in the format created by the "git format-patch" command as described in the instructions under the heading "Development" on this page: http://dev.clojure.org/display/design/JIRA+workflow

Show
Andy Fingerhut added a comment - Karsten, patches should be in the format created by the "git format-patch" command as described in the instructions under the heading "Development" on this page: http://dev.clojure.org/display/design/JIRA+workflow
Karsten Schmidt made changes -
Attachment byte-short-array-ctors.diff [ 11887 ]
Hide
Karsten Schmidt added a comment -

Sorry Andy, I used Atlassian SourceTree to create the patch and assumed it's in standard git format... I've removed the old one and attach a (hopefully) properly formatted one. Apologies, contributing-beginners-luck!

Show
Karsten Schmidt added a comment - Sorry Andy, I used Atlassian SourceTree to create the patch and assumed it's in standard git format... I've removed the old one and attach a (hopefully) properly formatted one. Apologies, contributing-beginners-luck!
Karsten Schmidt made changes -
Attachment byte-short-array-ctors.diff [ 11890 ]
Hide
Stuart Halloway added a comment -

While investigating this, I noticed that long-array coerces across type, e.g.

(seq (long-array [1.0]))
=> (1)

Is this what we want? I don't think so.

Show
Stuart Halloway added a comment - While investigating this, I noticed that long-array coerces across type, e.g.
(seq (long-array [1.0]))
=> (1)
Is this what we want? I don't think so.
Hide
Stuart Halloway added a comment -

I agree that all the numeric array constructors should work the same way, but I am not sue we should adopt long-array's approach, which allows coercion from float to integer types.

Show
Stuart Halloway added a comment - I agree that all the numeric array constructors should work the same way, but I am not sue we should adopt long-array's approach, which allows coercion from float to integer types.
Stuart Halloway made changes -
Approval Triaged [ 10120 ]
Rich Hickey made changes -
Approval Triaged [ 10120 ] Vetted [ 10003 ]
Rich Hickey made changes -
Fix Version/s Release 1.6 [ 10157 ]
Andy Fingerhut made changes -
Patch Code and Test [ 10002 ]
Alex Miller made changes -
Assignee Alex Miller [ alexmiller ]
Alex Miller made changes -
Description Example:

{noformat}
base64v3a=> (into-array Byte/TYPE [1 2 3 4])
#<byte[] [B@5ee04fd>
base64v3a=> (byte-array [1 2 3 4])
ClassCastException java.lang.Long cannot be cast to java.lang.Byte
  clojure.lang.Numbers.byte_array (Numbers.java:1418)
{noformat}

While into-array (via RT.seqToTypedArray) casts each element prior to inserting into the array, byte-array (via Numbers.byte_array) does an unchecked cast to Byte.

Current patch: byte-short-array-ctors.diff

The behavior of {{byte-array}} and {{short-array}} is inconsistent with the other {{<type>-array}} functions and with the {{into-array}} function when invoked with types other than byte or short. All of the other cases upcast to Number, then extract the primitive value, allowing this operation to succeed (assuming the value is in range). {{byte-array}} and {{short-array}} throw a ClassCastException.

Example:

{noformat}
base64v3a=> (into-array Byte/TYPE [1 2 3 4]) ;; int to byte ok
#<byte[] [B@5ee04fd>
base64v3a=> (byte-array [1 2 3 4]) ;; int to byte NOT ok!!
ClassCastException java.lang.Long cannot be cast to java.lang.Byte
  clojure.lang.Numbers.byte_array (Numbers.java:1418)
base64v3a=> (long-array [1 2 3 4]) ;; long to int ok
#<long[] [J@3f9f4d1d>
{noformat}

{{into-array}} (via {{RT.seqToTypedArray}}) and the other {{<type>-array}} functions all upcast to Number (via Numbers.<type>_array}}), then obtain the proper primitive value. {{Numbers.byte-array}} and {{Numbers.short-array}} do casts directly to Byte and Short (yielding the ClassCastException).

The attached patch makes the Byte and Short cases match the other types and the {{into-array}} behavior. Tests are included. The submitter is a contributor.
Hide
Alex Miller added a comment - - edited

I think the patch approach is valid. However, the patch does not cover the same problem in the 2-arity version of byte_array and short_array (when a size is supplied). Please update the patch to include a fix in the 2-arity version of byte_array and short_array and tests for the same. Ex: (byte-array 1 [1]).

Also, there is a whitespace issue in the patch - please just use spaces!

/Users/alex/work/code/clojure/.git/rebase-apply/patch:24: space before tab in indent.
	    	ret[i] = ((Number)s.first()).byteValue();
warning: 1 line adds whitespace errors.

Re Stuart's comments, I don't think that's in the scope of this ticket or solution.

Show
Alex Miller added a comment - - edited I think the patch approach is valid. However, the patch does not cover the same problem in the 2-arity version of byte_array and short_array (when a size is supplied). Please update the patch to include a fix in the 2-arity version of byte_array and short_array and tests for the same. Ex: (byte-array 1 [1]). Also, there is a whitespace issue in the patch - please just use spaces!
/Users/alex/work/code/clojure/.git/rebase-apply/patch:24: space before tab in indent.
	    	ret[i] = ((Number)s.first()).byteValue();
warning: 1 line adds whitespace errors.
Re Stuart's comments, I don't think that's in the scope of this ticket or solution.
Hide
Alex Miller added a comment -

Sending back to Karsten for the requested patch updates.

Show
Alex Miller added a comment - Sending back to Karsten for the requested patch updates.
Alex Miller made changes -
Approval Vetted [ 10003 ] Incomplete [ 10006 ]
Assignee Alex Miller [ alexmiller ] Karsten Schmidt [ toxi ]
Alex Miller made changes -
Description Current patch: byte-short-array-ctors.diff

The behavior of {{byte-array}} and {{short-array}} is inconsistent with the other {{<type>-array}} functions and with the {{into-array}} function when invoked with types other than byte or short. All of the other cases upcast to Number, then extract the primitive value, allowing this operation to succeed (assuming the value is in range). {{byte-array}} and {{short-array}} throw a ClassCastException.

Example:

{noformat}
base64v3a=> (into-array Byte/TYPE [1 2 3 4]) ;; int to byte ok
#<byte[] [B@5ee04fd>
base64v3a=> (byte-array [1 2 3 4]) ;; int to byte NOT ok!!
ClassCastException java.lang.Long cannot be cast to java.lang.Byte
  clojure.lang.Numbers.byte_array (Numbers.java:1418)
base64v3a=> (long-array [1 2 3 4]) ;; long to int ok
#<long[] [J@3f9f4d1d>
{noformat}

{{into-array}} (via {{RT.seqToTypedArray}}) and the other {{<type>-array}} functions all upcast to Number (via Numbers.<type>_array}}), then obtain the proper primitive value. {{Numbers.byte-array}} and {{Numbers.short-array}} do casts directly to Byte and Short (yielding the ClassCastException).

The attached patch makes the Byte and Short cases match the other types and the {{into-array}} behavior. Tests are included. The submitter is a contributor.
Current patch: byte-short-array-ctors.diff

The behavior of {{byte-array}} and {{short-array}} is inconsistent with the other {{<type>-array}} functions and with the {{into-array}} function when invoked with types other than byte or short. All of the other cases upcast to Number, then extract the primitive value, allowing this operation to succeed (assuming the value is in range). {{byte-array}} and {{short-array}} throw a ClassCastException.

Example:

{noformat}
base64v3a=> (into-array Byte/TYPE [1 2 3 4]) ;; int to byte ok
#<byte[] [B@5ee04fd>
base64v3a=> (byte-array [1 2 3 4]) ;; int to byte NOT ok!!
ClassCastException java.lang.Long cannot be cast to java.lang.Byte
  clojure.lang.Numbers.byte_array (Numbers.java:1418)
base64v3a=> (long-array [1 2 3 4]) ;; int to long ok
#<long[] [J@3f9f4d1d>
{noformat}

{{into-array}} (via {{RT.seqToTypedArray}}) and the other {{<type>-array}} functions all upcast to Number (via Numbers.<type>_array}}), then obtain the proper primitive value. {{Numbers.byte-array}} and {{Numbers.short-array}} do casts directly to Byte and Short (yielding the ClassCastException).

The attached patch makes the Byte and Short cases match the other types and the {{into-array}} behavior. Tests are included. The submitter is a contributor.
Alex Miller made changes -
Waiting On toxi
Hide
Karsten Schmidt added a comment -

Just replied to Alex, sorry JIRA emails went into spam - wasn't aware of recent comments... will make time to work on remaining issues early next week. Thx.

Show
Karsten Schmidt added a comment - Just replied to Alex, sorry JIRA emails went into spam - wasn't aware of recent comments... will make time to work on remaining issues early next week. Thx.
Alex Miller made changes -
Description Current patch: byte-short-array-ctors.diff

The behavior of {{byte-array}} and {{short-array}} is inconsistent with the other {{<type>-array}} functions and with the {{into-array}} function when invoked with types other than byte or short. All of the other cases upcast to Number, then extract the primitive value, allowing this operation to succeed (assuming the value is in range). {{byte-array}} and {{short-array}} throw a ClassCastException.

Example:

{noformat}
base64v3a=> (into-array Byte/TYPE [1 2 3 4]) ;; int to byte ok
#<byte[] [B@5ee04fd>
base64v3a=> (byte-array [1 2 3 4]) ;; int to byte NOT ok!!
ClassCastException java.lang.Long cannot be cast to java.lang.Byte
  clojure.lang.Numbers.byte_array (Numbers.java:1418)
base64v3a=> (long-array [1 2 3 4]) ;; int to long ok
#<long[] [J@3f9f4d1d>
{noformat}

{{into-array}} (via {{RT.seqToTypedArray}}) and the other {{<type>-array}} functions all upcast to Number (via Numbers.<type>_array}}), then obtain the proper primitive value. {{Numbers.byte-array}} and {{Numbers.short-array}} do casts directly to Byte and Short (yielding the ClassCastException).

The attached patch makes the Byte and Short cases match the other types and the {{into-array}} behavior. Tests are included. The submitter is a contributor.
Current patch: byte-short-array-ctors.diff

The behavior of {{byte-array}} and {{short-array}} is inconsistent with the other {{<type>-array}} functions and with the {{into-array}} function when invoked with types other than byte or short. All of the other cases upcast to Number, then extract the primitive value, allowing this operation to succeed (assuming the value is in range). {{byte-array}} and {{short-array}} throw a ClassCastException.

Example:

{noformat}
base64v3a=> (into-array Byte/TYPE [1 2 3 4]) ;; int to byte ok
#<byte[] [B@5ee04fd>
base64v3a=> (byte-array [1 2 3 4]) ;; int to byte NOT ok!!
ClassCastException java.lang.Long cannot be cast to java.lang.Byte
  clojure.lang.Numbers.byte_array (Numbers.java:1418)
base64v3a=> (long-array [1 2 3 4]) ;; int to long ok
#<long[] [J@3f9f4d1d>
{noformat}

{{into-array}} (via {{RT.seqToTypedArray}}) and the other {{<type>-array}} functions all upcast to Number via {{Numbers.<type>_array}}), then obtain the proper primitive value. {{Numbers.byte-array}} and {{Numbers.short-array}} do casts directly to Byte and Short (yielding the ClassCastException).

The attached patch makes the Byte and Short cases match the other types and the {{into-array}} behavior. Tests are included. The submitter is a contributor.
Hide
Alex Miller added a comment -

Updated patch to fix whitespace issues, add impl to include fixes in the other arity version of this function, added tests corresponding to the other arity version. Marking screened.

Show
Alex Miller added a comment - Updated patch to fix whitespace issues, add impl to include fixes in the other arity version of this function, added tests corresponding to the other arity version. Marking screened.
Alex Miller made changes -
Approval Incomplete [ 10006 ] Screened [ 10004 ]
Description Current patch: byte-short-array-ctors.diff

The behavior of {{byte-array}} and {{short-array}} is inconsistent with the other {{<type>-array}} functions and with the {{into-array}} function when invoked with types other than byte or short. All of the other cases upcast to Number, then extract the primitive value, allowing this operation to succeed (assuming the value is in range). {{byte-array}} and {{short-array}} throw a ClassCastException.

Example:

{noformat}
base64v3a=> (into-array Byte/TYPE [1 2 3 4]) ;; int to byte ok
#<byte[] [B@5ee04fd>
base64v3a=> (byte-array [1 2 3 4]) ;; int to byte NOT ok!!
ClassCastException java.lang.Long cannot be cast to java.lang.Byte
  clojure.lang.Numbers.byte_array (Numbers.java:1418)
base64v3a=> (long-array [1 2 3 4]) ;; int to long ok
#<long[] [J@3f9f4d1d>
{noformat}

{{into-array}} (via {{RT.seqToTypedArray}}) and the other {{<type>-array}} functions all upcast to Number via {{Numbers.<type>_array}}), then obtain the proper primitive value. {{Numbers.byte-array}} and {{Numbers.short-array}} do casts directly to Byte and Short (yielding the ClassCastException).

The attached patch makes the Byte and Short cases match the other types and the {{into-array}} behavior. Tests are included. The submitter is a contributor.
The behavior of {{byte-array}} and {{short-array}} is inconsistent with the other {{<type>-array}} functions and with the {{into-array}} function when invoked with types other than byte or short. All of the other cases upcast to Number, then extract the primitive value, allowing this operation to succeed (assuming the value is in range). {{byte-array}} and {{short-array}} throw a ClassCastException.

Example:

{noformat}
base64v3a=> (into-array Byte/TYPE [1 2 3 4]) ;; int to byte ok
#<byte[] [B@5ee04fd>
base64v3a=> (byte-array [1 2 3 4]) ;; int to byte NOT ok!!
ClassCastException java.lang.Long cannot be cast to java.lang.Byte
  clojure.lang.Numbers.byte_array (Numbers.java:1418)
base64v3a=> (long-array [1 2 3 4]) ;; int to long ok
#<long[] [J@3f9f4d1d>
{noformat}

{{into-array}} (via {{RT.seqToTypedArray}}) and the other {{<type>-array}} functions all upcast to Number via {{Numbers.<type>_array}}), then obtain the proper primitive value. {{Numbers.byte-array}} and {{Numbers.short-array}} do casts directly to Byte and Short (yielding the ClassCastException).

The attached patch makes the Byte and Short cases match the other types and the {{into-array}} behavior. Tests are included. The submitter is a contributor.

*Patch:* clj766-2.patch

*Screened by:* Alex Miller
Attachment clj766-2.patch [ 12214 ]
Alex Miller made changes -
Assignee Karsten Schmidt [ toxi ]
Rich Hickey made changes -
Approval Screened [ 10004 ] Ok [ 10007 ]
Stuart Halloway made changes -
Resolution Completed [ 1 ]
Status Open [ 1 ] Closed [ 6 ]

People

Vote (3)
Watch (6)

Dates

  • Created:
    Updated:
    Resolved: