How to know the concrete type of generics?

I want to write a method for collection types, filter out all nil and cast down the type.

class Array(T)
  def purge
     self.compact.map(&.as(T))
  end
end


a = [nil, 1, 2, nil] of Int32 | Nil
a = a.purge
p typeof(a[0])

After purge, Array(Int32 | nil) will be Array(Int32), but I don’t know how to make the code work.
Since T could be a compound type Int32 | nil, the code do nothing.

Thanks.

Hi!

Sorry, I don’t understand what you mean. Could you provide some code that shows what value/type you get, and what value/type you expect to get?

I think you would have to return a new array that doesn’t include the Nil type. This can already be done by using compact as you have.

https://play.crystal-lang.org/#/r/85h2

a = [nil, 1, 2, nil] of Int32 | Nil
 
p typeof(a[0]) # => (Int32 | Nil)
p typeof(a) # => Array(Int32 | Nil)
 
a = a.compact
 
p typeof(a[0]) # => Int32
p typeof(a) # => Array(Int32)
2 Likes

Note that you must use #compact (and not #compact!) and reassign the variable. This slight modification to the above code will not work:

a = [nil, 1, 2, nil] of Int32 | Nil

p typeof(a[0]) # => (Int32 | Nil)
p typeof(a) # => Array(Int32 | Nil)

a.compact! # <= THIS IS DIFFERENT

p typeof(a[0]) # => (Int32 | Nil)
p typeof(a) # => Array(Int32 | Nil)

https://play.crystal-lang.org/#/r/85hn

2 Likes

That’s exactly what I have tried, compact! So I thought compact will be same.

Thanks.