Open straight-shoota opened 1 year ago
Alternatively, we can at least simplify the implementation to use an array literal (which then gets expanded into a very similar code by the compiler, but the point is to avoid unnecessary repetition):
diff --git i/src/number.cr w/src/number.cr
index e7b21225e..8734eabd8 100644
--- i/src/number.cr
+++ w/src/number.cr
@@ -79,12 +79,7 @@ struct Number
# [1, 2, 3, 4] of Int64 # : Array(Int64)
# ```
macro [](*nums)
- Array({{@type}}).build({{nums.size}}) do |%buffer|
- {% for num, i in nums %}
- %buffer[{{i}}] = {{@type}}.new({{num}})
- {% end %}
- {{nums.size}}
- end
+ [{{ *nums }}] of {{ @type }}
end
# Creates a `Slice` of `self` with the given values, which will be casted
This macro became obsolete once we introduced autocasting. Without autocasting it makes sense because things like [1, 2] of Float64
didn't use to compile.
Because of the use of Number.new
, you can do this:
Int32[1.2, 3.4_f32, "56"] # => [1, 3, 56]
but not this:
[1.2, 3.4_f32, "56"] of Int32 # Error: expected argument #2 to 'Pointer(Int32)#[]=' to be Int32, not Float64
Though I wouldn't miss being able to do the former as those conversions seem like something the caller should do themself right at the call site.
(Also, oddly enough, Number.static_array
and Number.slice
use .new!
instead of .new
.)
A less intrusive solution is to move this macro to Number.array
instead, keeping the .new
semantics. I don't think there are any drawbacks in permitting e.g. BigInt.array(1, 2, 3)
.
Ah right, Big numbers don't support autocasting. So that's probably the only left practical use case / benefit over an array literal. [1, 2, 3] of BigInt
doesn't compile.
Speaking of the type grammer, today I was surprised that x : Int32[]
parses to (x : Int32).[]()
, which calls Nil#[]
because the receiver is a TypeDeclaration
that has no initializer.
Number.[]
is a convenience macro that allows to define anArray
of a specific numeric item type.Similar macros exist in the form of
Number.slice
andNumber.static_array
forSlice
andStaticArray
collections, respectively.But other than those I doubt this
Array
variant is very useful. It's semantically identical to an array literal with item type.The only difference is the token
of
. And the type is declared as a suffix instead of a prefix. Thus it's marginally shorter, but that's the only marginal benefit. The array literal syntax on the other hand is universal: it can be used with any type. Having a special alternative just for numeric types is unnecessary. It requires learning another concept for something that can be expressed with basic language syntax. And actually, there is a good chance for misinterpretation of what this macro means. In the type grammar,Float64[4]
is a short representation ofStaticArray(Float64, 4)
. AndStaticArray
also has a convenience macro of the same name, which could easily cause confusion. In the context ofStaticArray[1, 2, 3, 4]
creating a static array andFloat[4]
defining a static array type, one can reasonably doubt whatFloat64[1, 2, 3, 4]
actually means.I'm wondering if it makes sense to keep this convenience macro when it doesn't really provide much convenience and could instead be confusing, or if we should deprecate it.