Is there a way to convert an empty Tuple
into an array of a specified type?
I’m generating documentation based on user-definable commands. The argument declaration for the commands must be a Tuple
because they’re splatted and passed to a method on the command. I need to be able to turn that tuple into an array, but if the command doesn’t take any arguments, the Tuple
is empty, and tuple.map { |e| foo(e) }.to_a
returns an Array(NoReturn)
no matter what I do, including manual .as
inside the block and on the array.
Is there a way to go from Tuple()
to Array(T)
where T
isn’t NoReturn
? Or do I have to do the empty?
check manually?
This makes sense since the tuple is empty the map technically never runs at all and just returns another empty tuple.
I think your best bet is use a method with a freevar and check the size of the tuple type and key off that. E.g.
tup = Tuple.new
tup2 = {0, "foo"}
def tup_to_array(tup : Tuple(*T)) : Array forall T
{% if 0 == T.size %}
[] of String
{% else %}
[] of Union(*T)
{% end %}
end
pp tup_to_array(tup).class # => Array(String)
pp tup_to_array(tup2).class # => Array(Int32 | String)
But what’s the reasoning for needing it to be an array?
Explicitly creating the array may be helpful:
ary = [] of T
tuple.each do |e|
ary << foo(e)
end
1 Like
I’m passing the result to an object constructor that only accepts an Array
because it’s a JSON::Serializable
type. This object is part of a shard, but creating the data structure happens in my application.
Good call. I get so used to using map
that I sometimes forget that we can just do it the old-fashioned way.
1 Like
One thing I did for Athena is keep a reference to the Tuple
type itself, but store the values as an Array
, then use Tuple(*T) - Crystal 1.14.0 to build out the tuple to splat. It’s a pretty slick method. Not sure if it makes sense for your use case tho.