This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
RunasSudo-AWOLindefinitely's profile picture

OOP in Lua

Started by RunasSudo-AWOLindefinitely, 08 January 2013 - 04:37 PM
RunasSudo-AWOLindefinitely #1
Posted 08 January 2013 - 05:37 PM
OOP in Lua

Introduction to OOP
OOP (Object-oriented programming) is a style of computer programming that represents concepts as “objects” that have data fields (attributes that describe the object) and associated functions known as methods.

If you didn’t know that, this tutorial probably isn’t for you (this tutorial assumes at least some knowledge about OOP).

OOP in Lua
Lua does not have any OOP functionality, but one of its features – metatables – can be used to simulate OOP. A metatable in Lua is a table which describes another table (table-ception? no?)

Let’s Go!
Note: In this tutorial, I’ll be using Java terminology such as “class” and “constructor”. Just to clarify.
In this tutorial, we’ll be creating a “class” called Person, which has one field, name, three methods, getName(), setName(name) and toString(), and one constructor, new().

First off, we will define the Person “class”.
Person = {}
Person_mt = {}
Classes in Lua are represented by tables. The Person_mt table is a metatable which we will be using to describe the Person objects.

Now, we will define the setName, getName and toString methods.
function Person.setName(self, newName)
	self.name = newName
end

function Person.getName(self)
	return self.name
end

function Person.toString(self)
	return "Person object. name=" .. self.name
end 
But wait! What’s this mysterious self variable? Don’t worry. All will become clear later.

Now, we will define the the class constructor.
function Person.new()
	local personObject = { name = "" }
	setmetatable(personObject, Person_mt)
	return personObject
end
Okay, seriously, what is going on here? Don’t worry. I’ll go through these bits once we’re finished.

Finally, we need to set up the Person_mt metatable to do what we want.
Person_mt.__index = Person

At this point (after some reshuffling), the code looks like
Person = {}
Person_mt = {}

Person_mt.__index = Person

function Person.new()
	local personObject = { name = "" }
	setmetatable(personObject, Person_mt)
	return personObject
end
function Person.getName(self)
	return self.name
end
function Person.setName(self, newName)
	self.name = newName
end
function Person.toString(self)
	return "Person object. name=" .. self.name
end
Let’s go through this, section by section.

Person_mt.__index = Person
Like I said before, a metatable is a table which describes a table. When I call a function or access a field of a table, Lua checks the __index field of the associated metatable. This line tells Lua that when I call personObject:something, it should go to the Person table and look up something.

function Person.new()
	local personObject = { name = "" }
	setmetatable(personObject, Person_mt)
	return personObject
end
This code defines a function new() within the Person table. Writing Person.new is the same as writing Person["new"]. Just a little syntactic sugar. Firstly, it creates a new table, personObject, with a name field. Then it tells Lua which metatable to use for the personObject table. Finally, it returns the personObject table which now acts as an object.

function Person.getName(self)
	return self.name
end
When we call this function, we can either call Person.getName(personObject) or personObject:getName(). Notice the colon instead of full-stop in the second call. This tells Lua to find the getName function in Person_mt.__index and pass personObject as the first parameter.

The rest of the functions should be self-explanatory.

Now for some test code!
local personObject = Person:new()
personObject:setName("John")
print(personObject:toString())
Output:
Person object. name=John

OOP Pro Tip
String objects are also defined in this way, so instead of writing string.sub(variable, 5) you can write variable:sub(5).


Thank you for reading to the end of my somewhat messy explanation. Please leave constructive criticism in the comments (replies, whatever).
theoriginalbit #2
Posted 08 January 2013 - 05:41 PM
Nice tutorial! One typo tho, one too many end ;)/>

Now, we will define the the class constructor.
function Person.new()
	local personObject = { name = "" }
	setmetatable(personObject, Person_mt)
	return personObjectend
end
Orwell #3
Posted 08 January 2013 - 06:03 PM
Good tutorial. I like it that you actually explain stuff rather than listing some functions, like I've seen lately.. (Not that you could possible just 'list' OOP anyway :P/>)

I have 2 comments:
1. Not important at all, but it's kinda useless to use Person_mt as the metatable when it's just a reference to the Person anyway. I usually do this:

Person = {}
Person.__index = Person
then later on:

setmetatable(person_object, Person)
It is literally the same thing, but Person is the metatable, so why changing its name? :)/>

2. Not completely in the scope of OOP, but maybe handy to know.. You can define the field .__tostring as a member function return the string representation. print() will use tostring() which searches for this member function to retrieve a string representation of the table.
So if you'd add this:

function Person.__tostring(self)
  return self:toString()
end
Then you could print the person object with:

print(personObject)
It does also provide a nice example of function ("operator" in some contexts) overloading. :)/>
RunasSudo-AWOLindefinitely #4
Posted 08 January 2013 - 06:23 PM
Nice tutorial! One typo tho, one too many end ;)/>
Whoops! Thanks for pointing that out!

1. Not important at all, but it's kinda useless to use Person_mt as the metatable when it's just a reference to the Person anyway.
2. Not completely in the scope of OOP, but maybe handy to know.. You can define the field .__tostring as a member function return the string representation.
1. I mainly did it to make it less confusing and to reinforce that the metatable is (usually) a separate table. Does that make sense? :P/>
2. I know that (I didn't read the Lua reference manual for nothing :)/>). I just felt like including another method.
theoriginalbit #5
Posted 08 January 2013 - 06:24 PM
2. Not completely in the scope of OOP, but maybe handy to know.. You can define the field .__tostring as a member function return the string representation. print() will use tostring() which searches for this member function to retrieve a string representation of the table.
So if you'd add this:

function Person.__tostring(self)
  return self:toString()
end
Then you could print the person object with:

print(personObject)
It does also provide a nice example of function ("operator" in some contexts) overloading. :)/>

Expanding on that… there are more here… http://lua-users.org/wiki/MetatableEvents
RunasSudo-AWOLindefinitely #6
Posted 08 January 2013 - 06:28 PM
2. Not completely in the scope of OOP, but maybe handy to know.. You can define the field .__tostring as a member function return the string representation. print() will use tostring() which searches for this member function to retrieve a string representation of the table.
So if you'd add this:

function Person.__tostring(self)
  return self:toString()
end
Then you could print the person object with:

print(personObject)
It does also provide a nice example of function ("operator" in some contexts) overloading. :)/>

Expanding on that… there are more here… http://lua-users.org...MetatableEvents
More here (where I learnt about it): Lua Reference Manual 5.0 :P/>
theoriginalbit #7
Posted 08 January 2013 - 06:33 PM
2. Not completely in the scope of OOP, but maybe handy to know.. You can define the field .__tostring as a member function return the string representation. print() will use tostring() which searches for this member function to retrieve a string representation of the table.
So if you'd add this:

function Person.__tostring(self)
  return self:toString()
end
Then you could print the person object with:

print(personObject)
It does also provide a nice example of function ("operator" in some contexts) overloading. :)/>

Expanding on that… there are more here… http://lua-users.org...MetatableEvents
More here (where I learnt about it): Lua Reference Manual 5.0 :P/>
Same content. Yours was just a find the page and read, vs mine which was read :P/>

EDIT: I guess the document does have a little better explanation.
Orwell #8
Posted 08 January 2013 - 06:38 PM
1. I mainly did it to make it less confusing and to reinforce that the metatable is (usually) a separate table. Does that make sense? :P/>
No, I don't really get it. :P/> I know it's done in this way more often, but it's not a separate table. Not in any case of OOP I witnessed anyway. If you have a counter example, please show. :)/> Anyway, it's not that important. :P/>
RunasSudo-AWOLindefinitely #9
Posted 08 January 2013 - 06:44 PM
1. I mainly did it to make it less confusing and to reinforce that the metatable is (usually) a separate table. Does that make sense? :P/>
No, I don't really get it. :P/> I know it's done in this way more often, but it's not a separate table. Not in any case of OOP I witnessed anyway. If you have a counter example, please show. :)/> Anyway, it's not that important. :P/>
I just thought it might be a little confusing. "It's its own metatable, which means it describes itself, so when you call something in it, it looks up its metatable… which is itself… and finds the __index field… which is itself.. and then.. calls itself…?" Not a big deal either way.

"this.setmetatable(this, this)"
Whaaaa???
Orwell #10
Posted 08 January 2013 - 07:38 PM
* snip *
I just thought it might be a little confusing. "It's its own metatable, which means it describes itself, so when you call something in it, it looks up its metatable… which is itself… and finds the __index field… which is itself.. and then.. calls itself…?" Not a big deal either way.

"this.setmetatable(this, this)"
Whaaaa???
Well, it isn't its own metatable… Person/Person_mt is the metatable of personObject. And in the end, __index of both of those is Person. So Person is the metatable, and Person_mt is some sort of inherited object/table of Parent with the same properties. So in my opinion, it's just a synonym. But I guess it's just a matter of favor.
RunasSudo-AWOLindefinitely #11
Posted 08 January 2013 - 08:25 PM
Well, it isn't its own metatable… Person/Person_mt is the metatable of personObject. And in the end, __index of both of those is Person. So Person is the metatable, and Person_mt is some sort of inherited object/table of Parent with the same properties. So in my opinion, it's just a synonym. But I guess it's just a matter of favor.
See, even I'm confusing myself :P/>

Yay! I'm a Scripter now!
ChunLing #12
Posted 09 January 2013 - 12:09 AM
I have to admit, I'm…I've never really understood the point of object oriented programming. I mean, I totally get having different data types, but I don't get packing them into objects and then only interacting with those objects according to certain methods.

Perhaps it's because that's not at all how I approach real world objects. I'm totally comfortable taking them apart and arranging their basic elements to suit my current needs, and totally uncomfortable with things that are made to be difficult to disassemble and modify according to the situation. Of course, it's a two steps forward one step back kinda process. I guess that for every thousand dollars of time, effort, and money I save, I gotta blow at least a couple hundred somewhere by tinkering with something I shouldn't have tampered with. But usually that's because some idiot tried to make it tamper-proof.

That's what programming objects feel like to me, tamper-proofing. Tamper-proofing is for bombs and other front-end weapons, so that the enemy doesn't disarm them and use the components against you somehow.

Does that make me weird? Probably a little.
Orwell #13
Posted 09 January 2013 - 12:20 AM
I think that you are missing the point of object orientation. You can have a high level of abstraction and 'disassemblement' in OOP. Whilst most people see it as representing physical object as types, it doesn't have to be that way. There's a lot of theory that bridges modelling and programming. One of the major aspects is the link between concepts and types. These concepts can be very abstract and so can be the types derived from it. Benefits of OOP are abstraction, modularity (easy for debugging and updating), responsibilities (each object has a well defined task) and a lot more I can't think of right now.
RunasSudo-AWOLindefinitely #14
Posted 09 January 2013 - 12:51 AM
I have to admit, I'm…I've never really understood the point of object oriented programming.
Okay, so I want to represent a human in a data structure, but I know that later, I may add more things, so, I set up my classes as follows:
Human (is a) Biped (is an) NPC (is an) Entity
Now, anything a Biped can do (walk()) can be done by a Human, and anything an NPC can do can be done by a Human and so on.

If I wanted to do this in a procedurally oriented program……… Umm……………. Metatables?
Writing extends is just easier than copying over functions or doing crazy stuff with (already crazy) metatables…

Now you've probably got a pre-prepared rebuttal in your head from reading this common example.
darkroom #15
Posted 09 January 2013 - 07:12 AM
So could you give some more examples of OOP in Lua for example could you make a class that makes instances of drop down menus or something?
darkroom #16
Posted 09 January 2013 - 07:13 AM
Edit: Sorry double post
ChunLing #17
Posted 09 January 2013 - 07:14 AM
Not pre-prepared, but yeah…that's not how I view humans. Maybe it's how I should view humans (certainly, according to some).

I mean…probably it's not a good thing that I don't automatically discard the notion of adjusting someone's attitude with a screwdriver, but I don't. It's that simple, objects as they are defined by others tend to frustrate my native problem solving processes. Probably objects as they would be defined by me would be conceptually useless to others.

I guess I might actually like objects if i thought using a conceptual framework shared by more people.
theoriginalbit #18
Posted 09 January 2013 - 07:16 AM
an example is the vector api. have a read of that. and yes you could technically make drop down menus objects. you could make windows objects too. or buttons. or in my case I'm currently attempting to convert my Extended String Library to OO to make it easier for the programmer to implement and use.
Orwell #19
Posted 09 January 2013 - 07:38 AM
Not pre-prepared, but yeah…that's not how I view humans. Maybe it's how I should view humans (certainly, according to some).

I mean…probably it's not a good thing that I don't automatically discard the notion of adjusting someone's attitude with a screwdriver, but I don't. It's that simple, objects as they are defined by others tend to frustrate my native problem solving processes. Probably objects as they would be defined by me would be conceptually useless to others.

I guess I might actually like objects if i thought using a conceptual framework shared by more people.
an example is the vector api. have a read of that. and yes you could technically make drop down menus objects. you could make windows objects too. or buttons. or in my case I'm currently attempting to convert my Extended String Library to OO to make it easier for the programmer to implement and use.
That is a perfect example. You really don't need to limit OOP to representing physical objects and obvious relations. Objects are defined by behaviour, state and something else I can't remember. The state of a vector is the coordinates and the behavior is the combination of all operators. Using a procedural paradigm for vectors would be really not worth it.
ChunLing #20
Posted 09 January 2013 - 07:44 AM
Method. Interaction methods. And yeah, that's the exact sticking point for me.
Orwell #21
Posted 09 January 2013 - 07:56 AM
Method. Interaction methods. And yeah, that's the exact sticking point for me.
Its not clear to me anymore which point of view your defending. :P/> But methods are per definition object oriented.

There are people with authority in the field that swear by procedural programming and don't want to know about OOP. Alexander Stephanov, the creator of the STL library in C++ once stated this:
"I think that object orientedness is almost as much of a hoax as Artificial Intelligence. I have yet to see an interesting piece of code that comes from these OO people. In a sense, I am unfair to AI: I learned a lot of stuff from the MIT AI Lab crowd, they have done some really fundamental work: Bill Gosper's Hakmem is one of the best things for a programmer to read. AI might not have had a serious foundation, but it produced Gosper and Stallman (Emacs), Moses (Macsyma) and Sussman (Scheme, together with Guy Steele). I find OOP technically unsound. It attempts to decompose the world in terms of interfaces that vary on a single type. To deal with the real problems you need multisorted algebras - families of interfaces that span multiple types. I find OOP philosophically unsound. It claims that everything is an object. Even if it is true it is not very interesting - saying that everything is an object is saying nothing at all. I find OOP methodologically wrong. It starts with classes. It is as if mathematicians would start with axioms. You do not start with axioms - you start with proofs. Only when you have found a bunch of related proofs, can you come up with axioms. You end with axioms. The same thing is true in programming: you have to start with interesting algorithms. Only when you understand them well, can you come up with an interface that will let them work."
RunasSudo-AWOLindefinitely #22
Posted 09 January 2013 - 01:36 PM
EDIT: An extract from Head First Java about OOP vs POP: http://bit.ly/UMUMIv

that's not how I view humans
How would you represent, let's say a Human and a Pig in a data structure? Your code should be able to do anything my code can do.
My (loose) Java code follows:

Animal[] dataStructure;

abstract class Animal {
  final void speakData(String data) { print(data); }
  void speak() {}
  void move() { x += 3; }
}
class Human extends Animal {
  void speak() { speakData("Morning Guv'nor!"); }
  void walk() { move(); }
}
class Pig extends Animal {
  void speak() { speakData("Oink!"); }
  void trot() { move(); }
}
Edited on 10 January 2013 - 12:51 PM
ChunLing #23
Posted 09 January 2013 - 05:53 PM
The point is that I wouldn't represent a human at all. Or a pig. Not in any way that made a fundamental, categorical distinction between the two at the level of how I should deal with a particular instance of either. I don't know whether that's "philosophically unsound" or not, it's just that I wouldn't…or perhaps I simply can't. It's not a point I'm defending so much as a complaint I can't address to anyone in particular, because I wanted to say something complementary about the very good opening post but the topic is just one that doesn't sit right with me. In programming, even more than in real life, the imposition of a particular and rather irrational conceptual framework is…an unpleasant reminder of something unpleasant that I will not share anymore than can be divined from what I've already said.

On an unrelated note, Alexander Stephanov might be an authority in his field, but he should avoid making careless statements about mathematics. I don't believe it inexcusable for programmers to be somewhat ignorant about mathematics, but there are limits to what one can and cannot say without trespassing the bounds of complete nonsense.
theoriginalbit #24
Posted 09 January 2013 - 06:01 PM
the imposition of a particular and rather irrational conceptual framework

you know I was just thinking. Even other professions use classifications that can be thought similar to OO. For example Biologists classify living things by categories like mammal, marsupial, insect, etc… For example a monkey is a mammal, and a biped, a human is also a mammal and a biped, however a Platypus is a mammal but not a biped. Now if i was representing those animals in code, they classifications/modules would remain the same.

EDIT: If I were to attempt this in procedural programming…. well I wouldn't, I'd go for OO in a heartbeat…
I do understand that some people don't like OO, but in the end, sometimes it is better to use.
Edited on 09 January 2013 - 05:04 PM
ChunLing #25
Posted 09 January 2013 - 06:37 PM
I don't mind classifying things, the part that gets me is restricting the methods available for use by the class of "object" you're dealing with. Humans are notably different from pigs/insects/trees, this doesn't mean that there are no particular cases where it would be most appropriate to interact with one in a manner that would be more usual for the other. And being restricted from doing so is galling when that situation arises.
theoriginalbit #26
Posted 09 January 2013 - 06:41 PM
the part that gets me is restricting the methods available for use by the class of "object" you're dealing with.
To put it back to a real life context… What would happen if someone could just walk up to you and change anything about you, nothing about you is private, nothing is hidden, they have access to everything. What if they swapped your liver and stomach, then you tried to live and couldn't because someone had messed with you. Encapsulation is the prevention of people messing with stuff you don't want them to, because sometimes, if people do, then problems arise. And I quite like OO for this reason!
immibis #27
Posted 10 January 2013 - 01:08 AM
The point is that I wouldn't represent a human at all. Or a pig. Not in any way that made a fundamental, categorical distinction between the two at the level of how I should deal with a particular instance of either. I don't know whether that's "philosophically unsound" or not, it's just that I wouldn't…or perhaps I simply can't. It's not a point I'm defending so much as a complaint I can't address to anyone in particular, because I wanted to say something complementary about the very good opening post but the topic is just one that doesn't sit right with me. In programming, even more than in real life, the imposition of a particular and rather irrational conceptual framework is…an unpleasant reminder of something unpleasant that I will not share anymore than can be divined from what I've already said.

You're writing Minecraft. Humans and pigs are both entities. They might not share a lot, but they both have a position, need to be synced with clients, need to be saved and loaded, etc. How would you do that?
ChunLing #28
Posted 10 January 2013 - 08:51 AM
Well, java is object oriented, so of course I'd have to use classes.

But I wouldn't like it.

Also, IRL, the way I live it, having people come up and decide to rearrange my anatomy so as to discontinue my life processes is…one of those things I've learned to live with (not sure if that counts as a pun).
Edited on 10 January 2013 - 07:52 AM
Orwell #29
Posted 10 January 2013 - 09:18 AM
Well, java is object oriented, so of course I'd have to use classes.

But I wouldn't like it.

Also, IRL, the way I live it, having people come up and decide to rearrange my anatomy so as to discontinue my life processes is…one of those things I've learned to live with (not sure if that counts as a pun).
You're kind of avoiding the question. How would you implement what Immibis asked in C++ without OOP? Or even better, how would you go about implementing that in C, which practically has no OOP?
billysback #30
Posted 10 January 2013 - 11:39 AM
You're writing Minecraft. Humans and pigs are both entities. They might not share a lot, but they both have a position, need to be synced with clients, need to be saved and loaded, etc. How would you do that?

make a function which copies an array containing the data of both entities, changing the entity data that is required to change, have template arrays for each entity so that when you wish to run the function you can give it the template in one array and the relevant data in another, the function can then combine the two arrays in a sensible way and return you the result, you could then improve this to allow multiple templates, the templates at the front get the highest priority in the array listings. This way you could have a pig inherit "entity" "livingentity" and "pig" as well as the relevant information such as its location.

to sync it with clients encrypt each array in to a string then send the string off to the client, the client un-encrypts it and packs it back in to an array, if it already exists in the client send the entities ID and the changes encrypted.

to save and load encrypt and write each entity's array.

EDIT:
by the way, I don't really understand what this argument is about, is chun ling arguing that OOP is unnecessary or that it is almost insulting to strip down real world entities such as humans in to simple methods and variables, which to him are an unfair representation?
nitrogenfingers #31
Posted 10 January 2013 - 12:51 PM
You're writing Minecraft. Humans and pigs are both entities. They might not share a lot, but they both have a position, need to be synced with clients, need to be saved and loaded, etc. How would you do that?

Interfaces. Humans and Pigs share common fields and methods, exactly as you say, but inheriting from a superclass limits flexibility in both implementations. Pros and cons though, Interfaces retains polymorphism and has that flexibility, though you will usually have to write more code.

That's my main gripe with the OO paradigm, being restrained to the rules defined by the parent. If you want to insert something that fits the paradigm but not the implementation you have to either modify the superclass (opening back doors or possibly destabilizing other child classes), restrict what you want your new class to do, or start afresh. I guess OO works for much more detailed, strictly designed software, if you in SE and follow the waterfall or something, but most of us are agile programmers and I don't find the paradigm conducive to that design methodology.

Of course that's just an opinion, and it's an interesting subject for debate but I think this sort of thing is quite subjective.
Orwell #32
Posted 10 January 2013 - 01:33 PM
Interfaces are abstract classes and thus are per definition OO as well. My impression from the thread is that people are holding to strong to representing physical objects with OO. I got an exam on my course 'advanced programming' next week, so I got a lot of the theory fresh in my head. According to my text book, an object is defined by behavior, state and identity. When you are decomposing a problem and you can easily arrange it to concepts that define these 3 conditions, then OO seems like a wise choice to me. Those don't need to be physical objects, it can be vectors and points to do affine calculations for example. Also, in most cases, when working on larger projects, OO keeps things much more manageable. For smaller projects, like most CC programs, this hardly matters. (though, CC API's are often used in a OO way as well, like the term, fs and http api).

But in the end, it all starts at the problem decomposition. When it's easier to decompose it into smaller sequential problems, then the procedural paradigm is certainly a wise choice. I encounter this mostly with algorithms. On the other hand, when you can model the problem using concepts and types, OO would be the only smart choice. I'm working on Bounding Volume Hierarchies and GJK at the moment, I wouldn't know how I could ever implement that without OO.

A last note: While typing this, I realize that even in procedural programming in Lua, we are bound to use OO in some extent. File handlers for example are objects and I'm sure there are other objects you use in most programs.
RunasSudo-AWOLindefinitely #33
Posted 10 January 2013 - 01:45 PM
I just feel like pointing this out again:
http://bit.ly/UMUMIv
An extract from Head First Java about OOP vs POP.
Highlights the fact that some (but not all) programs just simply are less complicated in OOP.
ChunLing #34
Posted 10 January 2013 - 08:44 PM
See, I'm not opposed to having different types of data that are basically treated in different ways. I do sometimes want to turn strings into numbers and vice versa, but as long as I can I don't mind that strings and numbers are fundamentally different. In fact, I think that my fetish for maintaining type on a variable in Lua is somewhat unusual, judging by a lot of the samples I see.

So I don't have a problem with using classes to represent highly abstracted data objects, as long as there are methods that allow me to get/set (directly or indirectly) all the data in it's basic forms.

But the whole point of object oriented programming, what makes it different from normal use of arrays of data to represent things, is that you implement methods that are restrictive of what you can get or change (and how you can change it). Which may very well be a practical necessity in large projects to avoid having a poorly written section of the code screw things up for everyone else (and here we really are talking about people with markedly different skill levels all coding on the same project), but the fool-proofing….

Reminds me of some things that I'd as soon not talk about. I guess that makes it a bit of a conversational dead end.

Yes, there is also the issue of sheer elegance, unrestricted access to program data just lets you do things in a cooler way, generally and in many particulars. So we'll pretend that's what I'm on about and call it a day. Objects impose a clunky limitation on flexible data access, and the absolute benefits are limited (in pure computational theory, they don't exist at all, objects are purely drawbacks).
immibis #35
Posted 11 January 2013 - 12:34 PM
See, I'm not opposed to having different types of data that are basically treated in different ways. I do sometimes want to turn strings into numbers and vice versa, but as long as I can I don't mind that strings and numbers are fundamentally different. In fact, I think that my fetish for maintaining type on a variable in Lua is somewhat unusual, judging by a lot of the samples I see.

So I don't have a problem with using classes to represent highly abstracted data objects, as long as there are methods that allow me to get/set (directly or indirectly) all the data in it's basic forms.

But the whole point of object oriented programming, what makes it different from normal use of arrays of data to represent things, is that you implement methods that are restrictive of what you can get or change (and how you can change it). Which may very well be a practical necessity in large projects to avoid having a poorly written section of the code screw things up for everyone else (and here we really are talking about people with markedly different skill levels all coding on the same project), but the fool-proofing….

Reminds me of some things that I'd as soon not talk about. I guess that makes it a bit of a conversational dead end.

Yes, there is also the issue of sheer elegance, unrestricted access to program data just lets you do things in a cooler way, generally and in many particulars. So we'll pretend that's what I'm on about and call it a day. Objects impose a clunky limitation on flexible data access, and the absolute benefits are limited (in pure computational theory, they don't exist at all, objects are purely drawbacks).
You don't have to make all your fields private. And you'd still be using OOP if you didn't.
ChunLing #36
Posted 11 January 2013 - 01:50 PM
Yes and no. Yes, you're still using an Object Oriented programming language, but no you're really not using it for object oriented programming anymore if you bypass the essential difference between object oriented programming and non-object oriented programming. But it's not exactly like trying to eat soup with a knife and fork, or steak with a spoon.
immibis #37
Posted 12 January 2013 - 12:29 AM
Yes and no. Yes, you're still using an Object Oriented programming language, but no you're really not using it for object oriented programming anymore if you bypass the essential difference between object oriented programming and non-object oriented programming. But it's not exactly like trying to eat soup with a knife and fork, or steak with a spoon.
Just because you're not using every feature of OOP doesn't mean you're not using OOP. In the pig/human example, you'd still be using inheritance (both extend Entity to get the common behaviour of entities) and polymorphism (if you call ent.save() it saves all the relevant data, including the inventory of a player or the breeding cooldown of a pig).

It'd be more accurate to say you're not using encapsulation than to say you're not using OOP.

Edit: As far as I care, if you're using objects, and your methods are inside your objects (eg you have Entity.save instead of a global save_entity) you're using OOP. Even Wikipedia doesn't have a precise definition of what is OOP and what is not.
ChunLing #38
Posted 12 January 2013 - 04:03 AM
Sure,, it's a gradient. And on one end is "I can program naturally in this model" and on the other is "why the heck can't I get/set this value?".
RunasSudo-AWOLindefinitely #39
Posted 12 January 2013 - 01:15 PM
why the heck can't I get/set this value?
If something is set as "private" or "protected", there's usually a good reason for it (validation, need to keep track of stuff, etc) and you can usually get it in some form or another through some method. But, if you reealllly want to…

Object getPrivate(Object obj, String field) {
  Field f = obj.getClass().getDeclaredField(field); f.setAccessible(true);
  return f.get(obj);
}
Other languages probably have a better way of doing it, but whatever.

EDIT: Derp, spent so long in Lua I forgot the semicolons. And I wrote "function". And I forgot the return type. And I wrote "end".
Edited on 12 January 2013 - 12:26 PM
Orwell #40
Posted 12 January 2013 - 02:12 PM
why the heck can't I get/set this value?
If something is set as "private" or "protected", there's usually a good reason for it (validation, need to keep track of stuff, etc) and you can usually get it in some form or another through some method. But, if you reealllly want to…

Object getPrivate(Object obj, String field) {
  Field f = obj.getClass().getDeclaredField(field); f.setAccessible(true);
  return f.get(obj);
}
Other languages probably have a better way of doing it, but whatever.

EDIT: Derp, spent so long in Lua I forgot the semicolons. And I wrote "function". And I forgot the return type. And I wrote "end".
Not that many languages support something like reflection. I sure as hell know that C++ doesn't. :P/> But well, you just make a getter and/or a setter where needed and only where needed. :P/>
theoriginalbit #41
Posted 13 January 2013 - 12:49 AM
Now back to topic of OO in Lua… I have a question. Does anyone know if there is a way to do something to the effect of

object.__type
or is there anyway to add in so the following would work

local myObj = object:new()

print( type( myObj ) )
would print something like say "object"

EDIT: I do know about __tostring but was just wondering if support can be added for type
Edited on 12 January 2013 - 11:51 PM
Orwell #42
Posted 13 January 2013 - 02:22 AM
I searched thoroughly accross the internet, and type won't check for the __type metafield, or any other. Many suggestions were made to do this though. Depending on the situation, you could redefine type (I found some examples of that), or just plainly use the __type metafield?
theoriginalbit #43
Posted 13 January 2013 - 02:27 AM
I searched thoroughly accross the internet, and type won't check for the __type metafield, or any other. Many suggestions were made to do this though. Depending on the situation, you could redefine type (I found some examples of that), or just plainly use the __type metafield?

I wasn't even aware a __type metafield existed, I just meant something like it… I tried redefining and it didn't quite work how I wanted it to… I have another way to get to the desired outcome, just using type would have been nicer… oh well… thanks for the help :)/>
Orwell #44
Posted 13 January 2013 - 02:30 AM
I searched thoroughly accross the internet, and type won't check for the __type metafield, or any other. Many suggestions were made to do this though. Depending on the situation, you could redefine type (I found some examples of that), or just plainly use the __type metafield?

I wasn't even aware a __type metafield existed, I just meant something like it… I tried redefining and it didn't quite work how I wanted it to… I have another way to get to the desired outcome, just using type would have been nicer… oh well… thanks for the help :)/>
__type is only mentioned in some documents, I suppose that the functionality has been planned on earlier. Kaos had a nice type function in the other thread..
Eric #45
Posted 14 January 2013 - 12:39 PM
You can take the python approach, where most builtin functions look for a magic method first. For example:


local rawtype = type
local function metamethod(object, name)
    if rawtype(x) ~= "table" then return end
    local mt = getmetatable(x)
    if not mt or rawtype(mt) ~= "table" then return end
    return rawget(mt, '__'..name)
end
local function improve(name)
    local old = _G[name]
    _G[name] = function(x, ...)
        return (metamethod(x, name) or old)(x, ...)
    end
end
improve('type')
improve('next')
improve('unpack')
function repr(x)
    -- do stringification of tables and strings
end
improve('repr')
BigSHinyToys #46
Posted 23 January 2013 - 07:57 AM
I have to admit, I'm…I've never really understood the point of object oriented programming. I mean, I totally get having different data types, but I don't get packing them into objects and then only interacting with those objects according to certain methods.

Perhaps it's because that's not at all how I approach real world objects. I'm totally comfortable taking them apart and arranging their basic elements to suit my current needs, and totally uncomfortable with things that are made to be difficult to disassemble and modify according to the situation. Of course, it's a two steps forward one step back kinda process. I guess that for every thousand dollars of time, effort, and money I save, I gotta blow at least a couple hundred somewhere by tinkering with something I shouldn't have tampered with. But usually that's because some idiot tried to make it tamper-proof.

That's what programming objects feel like to me, tamper-proofing. Tamper-proofing is for bombs and other front-end weapons, so that the enemy doesn't disarm them and use the components against you somehow.

Does that make me weird? Probably a little.
I only know lua and have little understanding of OOP I can see how objects could be useful in some contexts making code cleaner and allowing reuse. I made this before I learn about OOP as it isn't really OOP but I think (could be wrong) shares some characteristics.

net api
http://pastebin.com/rBNb2vnq
test script
http://pastebin.com/0Dav7ga5

having simple components that react in predictable ways while being self contained allows programing of higher lever code not worrying about the lower lever work example calling a object to draw its self vs making a function to draw based from data in tables and other locations.

This tutorial has explained a lot of things I was having a hard time understanding. Thanks it is a great tutorial and I can see OOP being very helpful in future projects I work on.
H4X0RZ #47
Posted 02 May 2013 - 09:44 AM
I alway get an error:
Attemptbto call nil…

But I use the code of the OP.

Code:to be sure that I do it right

Person = {}
Person_mt = {}
Person_mt.__index = Person

function Person.new()
Local personObject = { name =""}
setmetatable(personObject, Person_mt)
return personObject
end

function Person.getName(self)
return self.name
end

function Person.setName(self, newName)
self.name = newName
end

function Person.toString(self)
return "Person Object. Name =" .. self.name
end

P1 = Person:new()
P1:setName("John")
print(P1:toString())

What did I do wrong?
theoriginalbit #48
Posted 02 May 2013 - 09:49 AM
-snip-
local does not have a capital L…

also as it was stated at some point you may as well remove the Person_mt table and just do this


Person = {}
Person.__index = Person

function Person.new()
  local personObject = { name = "" }
  setmetatable(personObject, Person)
  return personObject
end

function Person.getName(self)
  return self.name
end

function Person.setName(self, newName)
  self.name = newName
end

function Person.toString(self)
  return "Person Object. Name = " .. self.name
end

P1 = Person:new()
P1:setName("John")
print(P1:toString())
There was no point to create a table, just so it could point to itself.
GammaPaladin #49
Posted 05 October 2013 - 03:33 PM
why the heck can't I get/set this value?
If something is set as "private" or "protected", there's usually a good reason for it (validation, need to keep track of stuff, etc) and you can usually get it in some form or another through some method. But, if you reealllly want to…
If his experience is mainly coding minecraft mods, I could understand frustration with what variables are set private or protected. Notch's code is largely irrational, and seems to have had little thought put into what might need to be accessed externally (External to the class/object, not necessarily the net.minecraft.* package, but that too). Forge helps significantly, but yeah… Reflection is something you're going to probably need to become friends with if you want to mod minecraft in significant ways.

Not that many languages support something like reflection. I sure as hell know that C++ doesn't. :P/> But well, you just make a getter and/or a setter where needed and only where needed. :P/>
It depends on your definition of reflection. Technically, Java's access control manipulation isn't reflection per-se. It uses reflection, but it's a separate subject. Reflection is simply accessing classes/functions based on mapping string data to code names, which both C and C++ can do, though you don't see it that often.

But if in C I were to, say, create an enum storing a set of functions as pointers, and then read a string from a user's input and pull a matching entry from the enum, and call the pointer as a function, this would technically be reflection.
Kingdaro #50
Posted 05 October 2013 - 04:48 PM
-snip-
local does not have a capital L…

also as it was stated at some point you may as well remove the Person_mt table and just do this

There was no point to create a table, just so it could point to itself.
I hate writing "self".


function Person:getName()
  return self.name
end

function Person:setName(newName)
  self.name = newName
end

function Person:toString()
  return "Person Object. Name = " .. self.name
end

Also, it'd be neat bind the table's __call metamethod to its .new() method:

setmetatable(Person, { __call = Person.new })
But then you'd need to do that for every class, and at that point I'd just use a function to create new classes, so it does this for me.
jay5476 #51
Posted 05 October 2013 - 09:42 PM
to write something like minecraft you need OOP
every block has its
-hardness
-sound when stepped on
-data
you couldnt literally do seperate programming for each block especially with world gen
you can then count on OOP by making it so that every block is create from one main block with different parametres
so all grass blocks are made by this for example

--block file
public static final BlockGrass grass = (BlockGrass)(new BlockGrass(2)).setHardness(0.6F).setStepSound(soundGrassFootstep).setUnlocalizedName("grass").func_111022_d("grass");
creates a new block of grass wherever there needs to be

another example of OOP is C.O.D.B.O.2.
say theres an 5 exploding barrels they need to know how much damage they take before exploding if you try to handle them all at once as 1 thing then you damage 1 barrel enough all 5 explode but as objects they have their own damage values
OOP is used to distinguish each 'objects' feature
AgentE382 #52
Posted 06 October 2013 - 08:08 AM
You are misinformed. OOP is not needed to make something like Minecraft. It could be argued that OOP makes creating things like Minecraft easier, but it's certainly not necessary.

For example, there's a Minecraft server written in C, which is a procedural language. Also, LWJGL, which Minecraft uses for various tasks, including rendering, is a Java OOP wrapper around C procedural APIs.

I've also seen a First Person Shooter programmed in a strict functional language.

In case you didn't know, there are whole Operating Systems written in C. GNU/Linux is almost entirely C, the Mac OS X darwin kernel is written in C, and parts of Windows are still written in C.

You don't need OOP to do anything. Study the history of programming if you don't believe that claim. Or, you can look around and see that many games are still programmed without OOP, even though most games are programmed in C++ (an OO language) nowadays.

Note: This post is not attacking OOP, just pointing out a flaw in reasoning. Also note that it is technically possible to do OOP in C, because it's a general-purpose programming language. Also note that it is possible to program using the procedural paradigm in OOP languages, which is what many amateur Java programmers end up doing.
blm768 #53
Posted 12 October 2013 - 05:22 PM
I use OOP as a tool. If it's the right tool to model a system, I'll use it. If not, I'll use another coding style, and I'll freely mix paradigms. OOP is limited, but I find it to be a useful tool in specific situations.

As for implementing OOP in Lua, here's the code I use:

function class(super)
	local cls = {}
	local instance_mt = {__index = cls}
	function cls.new(...)
		local instance = {}
		setmetatable(instance, instance_mt)
		local initializer = instance.init
		if initializer then
			initializer(instance, ...)
		end
		return instance
	end
	if super then
		setmetatable(cls, {__index = super})
	end
	return cls
end

And to use the function:

local Shape = class()

function Shape:init()
	self.x = 0
	self.y = 0
end

local Circle = class(Shape)

function circle:init(radius)
	--Superclass constructors must be called explicitly:
	Shape.init(self)
	self.radius = radius
end

function Circle:draw()
	--Some code here...
end

local c = Circle.new(3)
ElvishJerricco #54
Posted 14 October 2013 - 09:14 PM
I hate writing "self".

Completely agree. This is why I dislike metatable based OOP so much. I greatly prefer using closures and setting their environments for instantiation. There's a tutorial somewhere around here about that. It's how LuaLua implements OOP.