savi-lang / savi

A fast language for programmers who are passionate about their craft.
BSD 3-Clause "New" or "Revised" License
156 stars 12 forks source link

Code generator bug with constructor calling other constructor #390

Closed mneumann closed 2 years ago

mneumann commented 2 years ago

These two should be identical, but they aren't:


:struct val MessagePack.Token
  :let _type MessagePack.Token.Type
  :let _size U8
  :let _value U64

  :new (@_type, @_value, @_size = U8[0])

  :new ext_ahead(type I8, len U32)
    @new(MessagePack.Token.Type.ExtAhead, type.u8.u64.bit_shl(32).bit_or(len.u64))
:struct val MessagePack.Token
  :let _type MessagePack.Token.Type
  :let _size U8
  :let _value U64

  :new (@_type, @_value, @_size = U8[0])

  :new ext_ahead(type I8, len U32)
    @_type = MessagePack.Token.Type.ExtAhead
    @_value = type.u8.u64.bit_shl(32).bit_or(len.u64)
    @_size = 0

Only the second example works!

Note that I have other constructors with single argument that work:

  :new map_ahead(len U32): @new(MessagePack.Token.Type.MapAhead, len.u64)
mneumann commented 2 years ago

Note ext_ahead! causes the problem

jemc commented 2 years ago

A constructor always makes a new instance, so if you call a constructor from within another constructor, the expected result is that two instances get created, but the inner one will be discarded because the outer one is the one returned to the caller.

In cases like the one you've shown, I'd usually make ext_ahead a :fun non that calls the constructor and returns the resulting instance. From the call site, it looks exactly the same as if ext_ahead was a constructor.

mneumann commented 2 years ago

ah, makes sense. Constructors have no return values.... My fault!