📜 ⬆️ ⬇️

Lua, OOP and nothing more

One day fate brought me to her. At first glance I was blinded and for a long time I could not take my eyes off her. Time passed, but she never ceased to amaze me, sometimes it seemed that I had studied her far and wide, but she turned over all my ideas again. There was no limit to her flexibility, and then I learned that she can also ... OOP!

Somehow, I seriously began to conquer the PLO in lua. And everything that I found on the Internet on this topic was a bunch of code with lots of underscores that did not fit into the elegance of this language. So I decided to look for a simple solution.

After reading a lot of smart books and analyzing several terrible implementations of the PLO, I, bit by bit, collected all the most useful and simple, until I had developed my style of object-oriented programming in lua.

Creating a class and instance


class Person
-- Person= {} --  function Person:new(fName, lName) --  local obj= {} obj.firstName = fName obj.lastName = lName --  function obj:getName() return self.firstName end -- ! setmetatable(obj, self) self.__index = self; return obj end --   vasya = Person:new("", "") --   print(vasya.firstName) --> :  --   print(vasya:getName()) --> :  


As you can see, everything is very simple. If someone gets confused where to put the period, and where is the colon, the rule is as follows: if we turn to the property, we set the period (object.name), if to the method, we put the colon (object: getName ()).
')
Further more interesting.

As it is known, OOP rests on three pillars: inheritance, encapsulation, and polymorphism. We will conduct a "debriefing" in the same manner.

Inheritance


Suppose we need to create a class inherited from the previous one (Person).

class Woman
 Woman = {} -- setmetatable(Woman ,{__index = Person}) -- masha = Woman:new("","") print(masha:getName()) --->:  


Everything works, but personally I do not like this version of inheritance, ugly. Therefore, I simply create the global extended () function:

extended ()
 function extended (child, parent) setmetatable(child,{__index = parent}) end 


Now class inheritance looks much more beautiful:

class Woman
 Woman = {}; -- extended(Woman, Person) -- masha = Woman:new("","") print(masha:getName()) --->:  


Encapsulation


All properties and methods up to this point in our classes were public, but we can also easily create private ones:

class Person
 Person = {} function Person:new(name) local private = {} --  private.age = 18 local public = {} --  public.name = name or "" -- "" -     --  function public:getAge() return private.age end setmetatable(public,self) self.__index = self; return public end vasya = Person:new() print(vasya.name) --> :  print(vasya.age) --> : nil print(vasya:getAge()) --> : 18 


Do you see? Everything is almost the same as you used to.

Polymorphism


It's still easier.

polymorphism
 Person = {} function Person:new(name) local private = {} private.age = 18 local public = {} public.name = name or "" --  ,    function public:getName() return "Person protected "..self.name end --  ,    function Person:getName2() return "Person "..self.name end setmetatable(public,self) self.__index = self; return public end -- ,   Person Woman = {} extended(Woman, Person) --     --   function Woman:getName() return "Woman protected "..self.name end --  getName2() function Woman:getName2() return "Woman "..self.name end -- masha = Woman:new() print(masha:getName()) --> Person protected  print(masha:getName2()) --> Woman  


So what did we do here?
- created the Person class, with two methods: getName () and getName2 (), the first one is protected from overriding;
- created the Woman class and inherited it from the Person class;
- redefined both methods in the Woman class. The first is not overridden;
- got a profit!

By the way, open methods can also be defined outside the class body:
polymorphism
 Person = {} function Person:new(name) local private = {} private.age = 18 local public = {} public.name = name or "" --  ,    function public:getName() return "Person protected "..self.name end setmetatable(public,self) self.__index = self; return public end --  ,   function Person:getName2() return "Person "..self.name end 


And what if you need to call the method of the base class, which we have overridden? This is also done easily!
The syntax is: ParentClass.Method (self_object, parameters (if any)).

class Woman
 -- ,   Person Woman = {} extended(Woman, Person) --     --  setName function Woman:getName2() return "Woman "..self.name end print(masha:getName2()) --> Woman  --    print(Person.getName2(masha)) --> Person  


P.S


That's all, I sincerely hope that at least someone this article will be useful.

Finally I will give the full code, you can copy it into the IDE and make sure it works.

Full code
 function extended (child, parent) setmetatable(child,{__index = parent}) end Person = {} function Person:new(name) local private = {} private.age = 18 local public = {} public.name = name or "" --  ,    function public:getName() return "Person protected "..self.name end --    function Person:getName2() return "Person "..self.name end setmetatable(public,self) self.__index = self; return public end -- ,   Person Woman = {} extended(Woman, Person) --     --  setName function Woman:getName2() return "Woman "..self.name end masha = Woman:new() print(masha:getName2()) --> Woman  --    print(Person.getName2(masha)) --> Person  

Source: https://habr.com/ru/post/259265/


All Articles