What is OOP used for? (Object Orientated Programming)

Hello! I did read the post about it where someone explains everything about them but I don’t really understand it. For example he says stuff like

local car = car.new()

As far as I know, you can only do

local car = Instance.new(--now size it so it looks like a car, I guess)

Can someone explain me what that whole thing even means? I’m really confused about OOP right now. Thank you!

5 Likes

Basically, instead of organizing your code into just detached functions (input and output, doesn’t edit anything), you organize into classes. Classes are tables that contain information about an object and functions relating to it. In the car example you used, you might use a SetColor function to set every part in the car’s color rather than repeating the same loop each time. The OOP part is the class — the fact that the function is associated with a car rather than just an abstract function.

4 Likes

Oh. So it’s about like making new classes? For example
local myTaco = taco.new()
lol?

not just, you can use it for anything you want

for instance I made this resource,
source: https://pastebin.com/uj3qH9Vy

but it’s primarily used for organization into classes, so you can implement features such as inheritance etc.

it’s not necessary to use OOP

1 Like

Thank you. Do you think I should learn that yet? I have about 7-8 months of experience. Is it not too early?

You never need OOP, you’d be fine without it. It’s just one way people like to organize their code.

6 Likes

It’s definitely worth learning, it’ll fall into the context of data structures. Like if you’re working with graphs its good to have vertex/ node classes which can be made through OOP.
But I see it much more of an organizational technique, I think understanding how code works is far more important in programming. Of course, it’s still good to know for simplifying some complex datatypes or elements.

1 Like

I generally use a metatable-based OOP approach, but not usually with particularly deep or plentiful use of inheritance. Most stuff is composed, and I tend to inject references down the hierarchy that ultimately starts from a Script or LocalScript loader. A few of the modules I use server-side are actual Singletons, like my Datastores module, my MarketplaceManager, and my PlayerLoadQueue. These really can’t be anything else, because they either use some Roblox API calls that mustonly be implemented once, like the ProcessReceipt callback, or it would make no sense to have more than one (like the queue that loads players, since the whole point is to avoid datastores throttling, which has a per-server-instance limit).

2 Likes

Thank you. I don’t fully understand it yet though. So could I just do something like

local MyCoolDataStore = DataStore.new()
local MyCoolBarn = Barn.new()

And why? Wouldn’t it just like print nil because it doesn’t even know what this is? How would it really create a barn, for example?

You have to define behavior for it yourself. You’d make a table called Barn and give it a function under the index new.

2 Likes

Well the most common way of implementing OOP with roblox is through module scripts. Something with the format like:

local customClass = {}
customClass.__index = customClass

function customClass.new() -- This is a constructor function; it creates the part
	local var = {}
	setmetatable(var, customClass)

	-- Class variables
	var.Name
	var.BrickColor
	var.Transparency

	return var
end

function customClass:foo() -- This is a class function; 

end

return customClass

Here’s a bit on how classes work with lua
https://www.lua.org/pil/16.1.html

It might be an easier concept to learn on a different language tho, possibly learn structs from c++

Edit: And heres how the server could use that customClass

customClass = require(<relative path to the module script>)

local customPart = customClass.new()
customPart.Transparency=1
customPart:foo()
1 Like

In simple terms, OOP is the concept of taking data and turning it into objects (technically known as classes). They allow you to assign functions to the data, and (for RBXLua) you can add events with Bindables (though you will need to manually clean these up when removing the object)

An example of a Car object in RBX.Lua could be
ModuleScript

local methods = {}
local Car = {}
methods.__index = methods --This is a metamethod, it allows us to point to the table's properties when called

function methods:Drive(spd)
   self.Speed = spd --self is a variable that is automatically created when you call a method with : (in the case you use . the first variable becomes the object itself
end

function Car.new()
   local o = setmetatable({}, methods) --this creates a new table that uses the same metamethods as methods
   o.Speed = 0 --property definition
   
   return o
end

return Car

Keep in mind, since objects in Lua are not primitive, there are many ways to create an OOP system, however they follow a general proceedure of providing a .__index method

1 Like

OOP is useful for when you are dealing with creation of lots of objects, because it’s easier to keep them all organised.

Let’s imagine you have a game where you spawn in zombies.

OOP is useful because you can have functions and methods tied into a class. So you could define your functions to make the zombie move, attack, find closest enemy, and also have properties of that zombie, such as HP. You’re also then able to keep track of all the spawned zombies in your game. Plus, it then makes it easier to spawn them.

And why? Wouldn’t it just like print nil because it doesn’t even know what this is? How would it really create a barn, for example?

Great Question. You would make a function called Barn.new() which clones your barn out of ServerStorage. You can pass parameters to this Barn.new() function such as the Position and then set the Barn’s position to that. Of course, without that, it would do nothing.

Also, metatables can come into play when using OOP. I won’t get too much into that (saving it for a tutorial) as it may confuse you especially if you don’t know much about them. Basically you have to create a table for your class, set the __index of it to itself, then define your functions inside that table as @greatgavin did, then inside your .new() function, create a blank table and make the first global table we talked about its metatable.

17 Likes

Deep breath

What is OOP

Object-oriented programming, as its name implies, is a paradigm (a way to write and think about your code), which is oriented around an object.

What is an abstraction

Before getting into anything, I want to quickly explain an abstraction. Abstraction is simply hiding implementation details from something. A good example is the Roblox API. It is an abstraction over a bunch of C++ code. Instead of working and interacting with C++ code directly it is made much more simple. Abstractions are extremely valuable since they let you focus on solving a problem elegantly. With good abstractions, you’ll probably never need to know the implementation details.

What is OOP [2]

The base concept of OOP, is, well, the object. An object is just like an object in the real world. They can have data (aka attributes), and “behaviors” (methods which perform on the object).

Let’s use a pizza as an example as an object. A couple of attributes it might have is:

  • Flavor
  • Slice count

And for methods it might have

  • Eat

(couldn’t think of any other lol)

When you define a function on an object like Pizza:Eat() that is called a method.

OOP’s purpose is to introduce objects as an abstraction level. We don’t care about how we eat the pizza we just want it to be eaten! OOP focuses on the what, not the how.

What are classes

Most object-oriented languages (like C#) have the concept of a class. Think of a class as a template, blueprint, whatever, for creating objects. You could use the Pizza class to create pizzas, or even a Car class (like your example) for cars.

When defining the class we specify the attributes and methods the object will have. When creating objects of a class we say it is an instance of the class. So a pizza could be an instance of the class Pizza.

Your code could look like this:

local Pizza = { }

function Pizza:Eat()
    -- Eat the pizza
end

Pretty epic, no? But, how do we actually make pizzas? That is where the constructor comes in. A constructor defines how we create an instance of a class, and returns it.

So your constructor could look something like

local Pizza = { }
Pizza.__index = Pizza

function Pizza.new(flavor, slice_count)
    local this = { }
    this.Flavor = flavor
    this.Slices = slice_count
    setmetatable(this, Pizza)
    return this
end

function Pizza:Eat()
    -- eat the pizza
end

From here you would call the constructor Pizza.new() to create a new pizza. The constructor takes some arguments, them being the flavor and how many slices it has.

local new_pizza = Pizza.new("Pepperoni", 8)
print(new_pizza.Slices)
print(new_pizza.Flavor)

You might be asking what I am doing with metatables and metamethods. You should already know about them. You don’t need them for OOP but a metatable approach is more simple. We use __index so we can define the methods outside of the constructor and keep them in 1 place rather than making new methods. And each instance of the pizza has the same metatable.

The : (colon) notation

function a:b(...)

end

is syntactic sugar (a nicer way to write something) for

function a.b(self, ...)

end

self is an implicit parameter that is passed when you use the : notation to define functions. An example to show this can be that workspace.Building:Clone() is sugar for workspace.Building.Clone(workspace.Building). You could pass any argument as the first one and it would be treated as self, i.e game.Destroy(workspace.Baseplate) would destroy the baseplate.

So this means that

function Pizza:Eat()

end

is the same as

function Pizza.Eat(self)

end

This syntax is very convenient as it allows to define methods. The .new() constructor does not use the : notation and is separate because it isn’t actually a method of the class.

What is inheritance

You can also have your classes inherit from other ones. For instance our Pizza class might inherit from a FastFood class. Your Car class might inherit from a Vehicle class. A class’ inheritor extends the class (Pizza extends the FastFood class), and the extended class is the superclass of the inheritor (aka subclass).

Inheritance can be implemented with metatables. We can use the __index metamethod to do just that.

Here might be the FastFood class:

local FastFood = { }
FastFood.__index = FastFood

function FastFood.new()
    local this = { }
    setmetatable(this, FastFood)
    return this
end

function FastFood:ThrowAway()
    -- throw the food away
end

Our pizza class constructor, remastered:

local Pizza = { }
Pizza.__index = Pizza
setmetatable(Pizza, { __index = FastFood })

function Pizza.new(flavor, slice_count)
    local this = { }
    this.Flavor = flavor
    this.Slices = slice_count
    setmetatable(this, Pizza)
    return this
end
local new_pizza = Pizza.new("Pepperoni", 8)
new_pizza:ThrowAway() -- you didn't like it :(

Remember again:

new_pizza:ThrowAway()

is the same as

new_pizza.ThrowAway(new_pizza)

new_pizza is that implicit self we were talking about earlier.

You’ve been using it all along!

You probably already knew this, but I’ma say it again. You’ve been creating new instances of the Instance class via Instance.new(). You’ve been checking if Instance:IsA("BasePart") to see if you’re working with an inheritor of BasePart, the superclass of Part, MeshPart, etc. You’ve been cloning these parts with the Instance:Clone() method (superclasses).

Should I use it?

I personally don’t. But other developers find that it allows the writing of better code. You don’t have to use the paradigm, and I (and many others) are able to write decent code without it.
You should at least try it, which it looks like you already have.

More on OOP

Yes, there is more. I only scratched the surface of OOP. There is more that you should definitely look into. I only talked about abstraction and inheritance, “pillars” of OOP.

  • Encapsulation (joining data into 1 unit; a class)
  • Polymorphism (where something can be multiple things)

  • Getters and setters
  • Access modifiers
  • Prototype-based OOP rather than class-based (JavaScript uses the former, you can do it in Lua too)

And more.

18 Likes