Simple OOP Plugin Actions

scripting
plugin
oop

#1

Another plugin!

I have been getting tired of creating new module scripts just to get the default ModuleScript source and then have to copy and paste different parts from my other scripts to get my script ready to work in. I use a very, very boiled down version of OOP that I don’t think anyone could really take offense with. It doesn’t require loading any libraries or even one use of the require function, it just works really easily.

To fix this, I created a plugin for simple OOP plugin actions to make it easy to create ModuleScripts with the default code for an empty class or singleton (two different actions), along with the documentation comments for my Documentation Reader plugin. You can hook up your own hotkey or use it from the quick access toolbar in Studio. I just think it will be helpful for those using OOP systems :slight_smile:

EDIT
By the way, the names of the plugin actions are “Create class” and “Create singleton” - unfortunately Studio’s UI isn’t very helpful for finding those on your own, and I unfortunately didn’t realize that until now.

Also, just for reference, here are the templates:

Class template
local Class = {}
Class.__index = Class

--[[**
	<description>
	Creates a new instance
	</description>
**--]]
function new()	
	local self = setmetatable({}, Class)
	
	return self
end

return {
	new = new
}
Singleton template
local Class = {}
Class.__index = Class

local instance = nil -- Singleton

--[[**
	<description>
	Creates a new instance
	</description>
**--]]
function new()	
	local self = setmetatable({}, Class)
	
	return self
end

return {
	GetInstance = function(...)
		if not instance then
			instance = new(...)
		end
		return instance
	end
}

#2

This is exactly how I’m structuring my OOP, so props for mind reading.

I use very similar conventions conventions:

I have a feeling this could be expanded into a much larger set of tools (that I would definitely use) if you made it into a widget panel.

For example, a button that allows the creation of inherited classes would be useful:

-- MainMenuInterface inherits Interface
MainMenuInterface.super = Interface.inherit()
MainMenuInterface.__index = function(self, key)
	return MainMenuInterface[key] or self.super[key]
end

In my code, I place an “inherit” function in the same table as the “new” constructor.

You could probably also add a quick button for wrappers to a panel like that, though I’m sure people might take offense to this (and inheritance wouldn’t be so feasible with the way I’ve implemented it so far):

It would be cool to have some sort of dialogue that automatically creates modules with parameters like a name, inheritance, etc.


#3

So this is where programmers get upset because there is no easy way to agree on an exact method of programming.

Anyway, after a long time (and I mean a very long time) of working with inheritance in Lua OOP, I decided I never wanted to touch it again. I find that it is much easier, cleaner, and simpler to just use duck typing and to use component-based programming. For instance, my Player DataStore Cache Script is just a component that I use in a variety of singleton “Service” classes to store data for users in a DataStore. I was previously using inheritance to do exactly that. If I absolutely need to expose a function from one component of an object, I can either make the component a public property of the class or I can wrap the function.

So, I’m sorry to say that it is very unlikely I will ever develop a Studio plugin to encourage the use of Lua OOP inheritance structures.

That said, I do see myself moving towards using plugin settings and allowing developers to create their own templates and use the same plugin actions for those. If I can figure out a way to do it, I may even just let developers create an infinite number of templates and have a plugin action for each one. And I would definitely use dock widgets for that. Expect that update in a week or two :slight_smile: Just gotta wait till I finish up a couple other things and then that’ll be a priority.

EDIT
I feel it would also help to clarify that the catalyst for me to move away from inheritance structures was a desire to be able to easily open source my code. Having to have people put in multiple scripts just to build my wacky inheritance trees that would likely not fit into their game’s systems was a big problem for me. So, after several months of considering switching, that did it in for me.


#4

I pick a programming model depending on the problem I’m solving, but I usually go with component-based programming with dependency injection.
Most lua-based classes are overly-confusing and complicated, so I just stick with something simple:

local Class = {}
local Methods = {}
local Metatable = {__index = Methods}

function Methods:SomeMethod()
	print(self.Something)
end

function Class.new()
	return setmetatable({
		Something = 1;
	}, Metatable)
end

return Class

#5

So I’d rather not have this thread become a “you should OOP this way!” thread haha. I explained how I do things as an explanation for why I wouldn’t add a feature, and I realize now that that may have been a mistake to do.


#6

Interesting. I definitely don’t use OOP for everything (I use “Service” classes that are just normal tables of functions, with an “Init” function that is called at runtime after a preliminary require of all service classes, allowing services to interface with each other while preventing circular dependencies).

However, I do use OOP for any non-singleton classes that I want to share code for. Inheritance is often useful for this (especially with the “interface” I’ve made for front-end UI stuff, which allows for easy cross-platform support).

With RBXLua, there is not always a standard, correct way of doing things. I still have some minor use cases for inheritance though.

edit: Oh, you just ninja’d my derailment of the thread.

I wonder if it would be possible to make some sort of plugin that lets users somehow choose their conventions, given certain arguments. Maybe just call it a “script template inserter” or something, and then have some sort of custom syntax to let users input parameters to create a script from a given template.

That would actually be helpful for creating things like a “service” class, or some of the OOP classes that I also use on occasion.


#7

The more I think about it, the more I think that will actually be a plugin of its own that I’ll make, and I will probably just completely moonlight this plugin in a week or two :joy: I’ll just have my own conventions, the ones shown in this thread’s OP (now updated), as defaults.