Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interfaces that contain nested records might need to generate Lua code #870

Open
mtdowling opened this issue Dec 7, 2024 · 2 comments
Open

Comments

@mtdowling
Copy link

mtdowling commented Dec 7, 2024

I was playing around with trying to find a class style pattern I like with the new interface features, so I tried this:

local interface State
    update: function(self: State, dt: number)

    -- a metatable that you can use to get default implementations
    record mt end
end

State.mt = {
    __index = {
        update = function(self: State, dt: number)
            print("default update")
        end
    }
}

-- Now make a State.
local record GameState is State end
setmetatable(GameState, State.mt)
local gameState_mt: metatable<GameState> = {__index = GameState}

function GameState.new(): GameState
    return setmetatable({}, gameState_mt)
end

function GameState:foo()
    print("foo")
end

local game = GameState.new()
game:foo()
game:update(1)

This fails because State is elided from the generate code:

State.mt = {
   __index = {
      update = function(self, dt)
         print("default update")
      end,
   },
}


local GameState = {mt = {}, }
setmetatable(GameState, State.mt)
local gameState_mt = { __index = GameState }

function GameState.new()
   return setmetatable({}, gameState_mt)
end

function GameState:foo()
   print("foo")
end

local game = GameState.new()
game:foo()
game:update(1)

A very similar pattern using records would work (basically just make State a record and remove the is).

So either:

  1. This is maybe philosophically against how interfaces are supposed to work and it's just a gap in validation that nested records are allowed.
  2. Or maybe when nested records are detected in interfaces, the interface needs to generate a container in the Lua code.
@Hedwig7s
Copy link

Interfaces are abstract. They should have no output
Use records for this (or use an interface and a record and type record as the interface)

@mtdowling
Copy link
Author

I think that's a reasonable take (option 1 above). I see other issues in this repo where people tried to nest a record in an interface. A simpler reproduction:

local interface Foo
    record Baz
        x: number
    end
end

function Foo.Baz.new(x: number): Foo.Baz
    return {x = x}
end

It seems that the compiler should prevent nesting records in interfaces.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants