Recently, I started thinking about a project that I would like to make with Defold and ink in a quite distant future.
However, since there are no maintained Lua implementation of the ink runtime, I thought about writing one myself.
I have little experience with Lua (but I’m not new at programming), so I don’t really know where to start to translate the official C# implementation into Lua.
I’d like to keep the Lua library as close as possible to the C# one so that it is easier to maintain, and that would mean using OOP.
So the question is, is it better to implement the objects with closures or with metatables? It seems that closures are faster, but take more memory.
I want to keep the library generic so that it works in any environment, but since I will mainly use Defold, I’d like to know what is best for it.
And if you don’t think OOP is the way to go with Lua, then how do you think I should structure the library?
(Since all of this is in a distant future, anyone wanting to write the library before me is welcome to do it!)
I prefer closures. It doesn’t hide behavior in metatables.
But in general I don’t think it is a very good idea to try and replicate the OO design of a library written in another language. It will probably not be easier to maintain. Use the same kind of naming and try to replicate the public API but make the underlying implementation Lua friendly.
I was thinking it would be easier to maintain in the sense that the Lua implementation would “mirror” the C#. So when the C# implementation is updated, I would “just” report the modifications to the Lua library without to much searching what has been modified.
Could you give me an example of a “Lua-friendly implementation”?
Ink works like the following:
--- This is some kind of pseudo-code
ink = require(ink)
-- Create the story representation
-- from the JSON file created by ink.
story = ink.Story.new(json.decode(my_story_json))
-- Get the next line of the story.
if story.can_continue() then
next_line = story.continue()
end
-- Get the list of available choices
choices = story.current_choices()
-- Select a choice.
story.choose_choice_index(1)
-- Save and load the story state.
story_state = story.state.to_json()
story.state.load_json(story_state)
So without OOP, how would it look? It seems obvious to me that the story representation has to be a table. But how would I implement the methods? In that particular case, having the story encapsulated into an object looks like an appropriate solution, at least to me.
I didn’t know a Haxe port existed , but I’ll have a look. How would the performance be? I tried the JavaScript example, and there is a noticeable delay that isn’t there with the JavaScript implementation written from scratch.
But if it works acceptably, I could use it as a proof of concept, before writing a Lua implementation.
A non oop api would look like ink.can_story_continue(story_id) instead of story.can_continue(). You keep a data structure with all story data in one place and pass a reference/id to access the data.
Sorry if I seem slow to understand, but are we talking about remove the OOP from the public API only? If that’s the case, then I don’t really see the point, except if we want to follow Lua’s conventions (which is admittedly a legitimate reason).
But if we are talking about removing the OOP from the underlying code, that would mean refactoring entirely the whole library, which seems to me a major pain and likely to introduce lots of bugs.
Sorry if the discussion drifted a bit away from Defold, and thanks for the answers. As I said, it’s not urgent, so I’ll think about it before starting this project.
What I meant with my non oop api example was to show that you could design your Lua version of the library in a way that the names of the public api functions are very similar to the api for other versions.
If you want to port line by line from another language then go for the oop version using closures or metatables.
Yes, I saw that Lua is multi-paradigm. But it’s not because we can do OOP that we should. It depends on the use case and on the conventions of the language (and it’s what I was asking).
I’ll still think about it for a while before starting my project.