The Crystal Programming Language Forum

Pointers in classes and methods

I’m experimenting with pointers and there is one thing I do not understand.

I have this little code:

var1 = 0x01023304_u32
 
p! var1
 
pt = pointerof(var1)
p! pt
ptr = pt.as(Int8*)
 
p! ptr
p! ptr[0]
p! ptr[1]
p! ptr[2]
p! ptr[3]
 
tt = Testme.new
tt.test(var1)
 
 
class Testme
  def test(var : UInt32)
    @var2 = var
    p! @var2
    point
  end
  
  def point
    prt = pointerof(@var2)
    p! prt
    prt8 = prt.as(Int8*)
    p! prt8
    p! prt8[0]
  end
end

The output is something like that:

var1 # => 16921348
pt # => Pointer(UInt32)@0x7fffe01f7424
ptr # => Pointer(Int8)@0x7fffe01f7424
ptr[0] # => 4
ptr[1] # => 51
ptr[2] # => 2
ptr[3] # => 1
@var2 # => 16921348
prt # => Pointer((UInt32 | Nil))@0x7f453bd19f48
prt8 # => Pointer(Int8)@0x7f453bd19f48
prt8[0] # => -90

The pointer ptr outside the class works as expected. It brings me the single bytes.

But in the class method there is something going on I do not understand. Do somebody know why the meaning of

Pointer((UInt32 | Nil))

Why is there a Nil in the pointer from the class? And for what is this good for?

The second pointer have a diffrent address - ok. But should be behind this address there the same value from var2?

Thanks a lot for helping

@var2 wasn’t initialized in the initialize method so it’s considered to be nilable.

I was going to link to the reference to the part that explains this, but I couldn’t find it. I think that explanation is missing.

In any case, this is unrelated to pointers. If you don’t initialize an instance variable in the constructor (initialize) the compiler will consider it as also having the type Nil.

The type of @var2 is deduced to be UInt32 | Nil (you can check typeof(Testme.new.@var2)). The ivar is not assigned in the constructor, so when you create an instance of Testme the value is nil by default.
That’s different from var1 which is assigned a UInt32 value as soon as it is declared.
The different value for ptr[0] comes from that union type, because the pointer does not point directly to the UInt32, it is prefixed by a type id to determine if the value is Nil or UInt32.

Thanks a lot!

I added the initialize to the class:

  def initialize(@var2 : UInt32 = 0)
    
  end

And now I get for both pointers the same value. The Nil in the “class”-pointer is disapeard as well.

merci!