Double splatting a union (NamedTuple(...) | NamedTuple(...)) is not yet supported

For this question, The things what i want to do is like following Ruby code:

options = {foo: true}
options[:bar] = "String" if true
options

def some_method(**options)
  p options
end

some_method(**options)

current, my solution is: (probably do things a wrong way, please point it out)

options = {foo: true}
options = options.merge(bar: "String") if true
p options         # => {foo: true, bar: "String"}
p typeof(options) # => (NamedTuple(foo: Bool) | NamedTuple(foo: Bool, bar: String))

def some_method(**options)
  p options
end

some_method(**options)
# Error: double splatting a union (NamedTuple(foo: Bool) | NamedTuple(foo: Bool, bar: String)) is not yet supported

So, how to fix it? or, is there a more practical way to achieve this?

Thanks.

You have got the understanding of Tuple, NamedTuple wrong. They are fixed-size, immutable, and stack-allocated objects, whose type need to be known at compile time.

What you are accomplishing is a runtime behavior, so you should be leaning toward approach that works for your cited use-case.

if you insist to use double splatting, then you can create NamedTuple from Hash (something like below) though I don’t see any reasoning for following such approach:

options = {:foo => true} of Symbol => Bool | String

options[:bar] = "String" if true
p options         # => {:foo => true, :bar => "String"}

p typeof(options) # => (Hash(Symbol, Bool | String)

def some_method(**options)
  p options # => {foo: true, bar: "String"}
end

some_method(**{foo: Bool, bar: String}.from(options))

HIH

1 Like

Thank you very much, this is the expected solution.(Use hash is enough)

I never use hash like this. (i only use of to initialize a empty hash)

options = {:foo => true} of Symbol => Bool | String

Could you please tell me, what is the different with following(not working) code?

options : Hash(Symbol, Bool | String) = {:foo => true}
 14 | options : Hash(Symbol, Bool | String) = {:foo => true}
      ^------
Error: type must be Hash(Symbol, Bool | String), not Hash(Symbol, Bool)

I would say that should be undesired behavior from compiler when var is defined and initialized with value.

You can overcome such restriction either by declaring the type

 options = {} of Symbol => Bool | String
 .....

OR

casting a value to that of union type

alias VType = Bool | String
options : Hash(Symbol,VType) = {:foo => true.as(VType)}
....

HIH

1 Like