Help with Union Types

#1

I guess I have not understood how do deal with Union Types.
Please have a look to the following code:

class Weird
  property val : Int32 | Nil

  def initialize
    @val = nil
  end

  def initialize(@val)
  end

  def add(n : Int32)
    if !@val
      @val = 0
    end
    @val += n
  end
end

a = Weird.new 9
a.add(19)

val can either be Nil or an Int32
In the add method I wanted to add n to val after I initialized val to 0.
Unfortunately the compiler says: undefined method ‘+’ for Nil (compile-time type is (Int32 | Nil))
I have no clue how to solve that.

Any hints

0 Likes

#2

You can do something like this: https://carc.in/#/r/6iyr

class Weird
  property val : Int32?

  def initialize
    @val = nil
  end

  def initialize(@val)
  end

  def add(n : Int32)
    val = @val || 0
    @val = val + n
  end
end

a = Weird.new 9
p a.add(19)

b = Weird.new
p b.add(42)

Basically:

# set a local variable to the value of @val, or 0 if it's nil
val = @val || 0  
@val = val + n
0 Likes

#3

The issue is that the types of instance variables won’t be restricted by if checks. See the limitations of if var in the documentation

Using a local variable, the following code would work as expected:

typeof(val) # => Int32 | Nil
if !val
  val = 0
end
val += n

But instance variables work differently. They can be accessed from different execution contexts. For example, when the value is Int32, the if !@val check is false and execution proceeds to @val += n. However, in between those two expressions a different fiber could have changed the value to nil and everything would explode.

(This is currently mostly theoretical, because in a single-threaded environment, there is no way a fiber change could happen between those two expressions because there is no IO, sleep or similar. But the language is already prepared for multi-threading, which is currently beginning its early steps.)

0 Likes

#4

Just a side note: you also do not need two constructors, the following one would do the same:

def initialize(@val = nil); end
0 Likes

#5

Great, that works.
Thank’s for all your hints

0 Likes