Union types in runtime

81 Views Asked by At

Can anyone explain how the compiler generates the code that will work for union types in runtime. For example, I have this crystal code:

def myfunc : Int32 | String
  if Time.utc.to_unix % 2 == 0
    return 1
  else
    return "a"
  end
end

x : (Int32 | String) = myfunc
puts x * 2

I have a function that can return either int or string. And I do not know what type I will have until runtime. But I have "*" function that has different behaviour for different types. For int it just doubles the number (we get 2), but for string it concatenates the string (we get "aa"). How do we know in runtime what actually should we do with the value in x since we do not have types in runtime?

1

There are 1 best solutions below

2
Johannes Müller On BEST ANSWER

The union type value has a type id embedded which describes at runtime which type it is (this information is available as an undocumented method Object#crystal_type_id).

The implementation of the union types' #* method then uses multi dispatch to call the respective runtime types' implementation. It can be thought of as somethign like this:

fun "(Int32 | String)#*"(*args)
  case crystal_type_id
  when String.crystal_instance_type_id
    "String#*"(*args)
  when Int32.crystal_instance_type_id
    "Int32#*"(*args)
  end
end