Object-oriented implementation in Lua

Source: Internet
Author: User

 

Metadata table concept

 

In Lua, the object-oriented method is implemented using the meta-table mechanism. The meta-table is a very "Taoist" mechanism, which is very profound and powerful. It has some basic concepts that are hard to understand. However, only by fully understanding the meta-table can we be able to use Lua's object-oriented skills and be able to write the advanced Syntax of Lua code.

 

First, in general, a table is different from its metadata table (not the same table). When creating a new table, the metadata table is not automatically created.

However, any table can have a metadata table (this capability exists ).

 

E.g.

T = {}

Print (getretriable (t) --> nil

T1 = {}

Setretriable (t, t1)

Assert (getretriable (t) = t1)

 

Setretriable (table 1, Table 2) mounts table 2 to Table 1 and returns Table 1 after mounting.

 

The _ resumable field in the metadatabase is used to hide and protect the metadatabase. When a table is connected to a meta table with a value of _ resumable, the value of the field _ resumable is returned when you use getretriable to operate the table! If you use setretriable to operate the table (that is, assign a new metadata table to the table), an error is thrown.

 

Table: 0x9197200

Not your business

Lua: Comment est. lua: 12: cannot change a protected writable able

Stack traceback:

[C]: in function 'setretriable'

Sort est. lua: 12: in main chunk

[C]:?

 

_ Index Method

 

The _ index meta method in a metadatabase is a powerful metadatabase method that provides support for backtracking queries (READS. The implementation of object-oriented search is based on backtracking.

When you access a field that does not exist in a table, the result is nil. This is correct, but it is not completely correct. In fact, if this table has a metadata table, this access will prompt Lua to find the _ index metadata method in the metadata table. If this metadata method is not available, the access result is nil. Otherwise, the meta method provides the final result.

 

_ Index can be assigned as a function or a table. When it is a function, call this function, pass in the parameter (what is the parameter later), and return several values. When a table is created, the table is accessed again in the same way. (When it is a table, __index is equivalent to the meta field. It is better to clearly distinguish it, although everything in Lua is a value)

 

Note: At this time, three tables are displayed. This is easy to get dizzy. Let's take a look.

The table we directly operate on is called Table A, and the meta table of Table A is called Table B. The _ index field of Table B is assigned to the table, which is called Table C. The whole process is like this. If you cannot find A field in Table A, you will check whether Table B of Table A has any metadata. If yes, check whether the _ index field in B has a value assignment, and whether the value assignment is in Table C. If yes, go to C to find the field you want to access. If yes, the field value is returned. If no value is found, nil is returned.

 

For tables without meta-tables, access a non-existent field and a nil is returned directly.

 

_ Newindex is the method corresponding to _ index. Its function is "Update (write)", and the two are complementary. Here we will not elaborate on _ newindex, but the process is very similar. the flexible use of the two elements will produce a lot of powerful results.

 

From the inheritance perspective, the initial effect can be achieved using _ index.

 

Object-oriented implementation

 

Lua is a prototype language. A prototype is a common object. When other objects (instance of the class) encounter an unknown operation, the prototype searches for the prototype. To represent a class in this language, you only need to create a prototype dedicated to other objects. In fact, classes and prototypes are both a way of sharing behavior between organizational objects.

 

The implementation prototype in Lua is very simple. In the three tables analyzed above, C is the prototype of.

 

After the principles are explained, let's have some tips. In fact, the three tables mentioned above are not necessarily completely different. A and C can be the same. Let's look at the example below.

 

A = {}

Setretriable (A, {_ Index = })

 

At this time, it is equivalent to a's prototype, and a's own prototype. It is a very interesting word. That is to say, when searching, you won't go to other places if you cannot find it on yourself. However, the prototype itself is not very useful. If a can be a class and the new object generated uses a as the prototype, this will be useful for further interviews.

 

Again, you can also use your own table metadata. That is, a can be a meta table.

 

A = {}

Setretriable (A,)

Now you can write it like this,

A. _ Index = table or function

You can use your own meta table if. _ index is a given table. At least one table can be generated in the memory. If. _ index is a function, which produces very concise and powerful results. (_ Index is a field. Isn't it very concise)

 

Then, the metadata table B and the prototype Table C can be the same.

A = {}

B = {}

B. _ Index = B

Setretriable (A, B)

In this case, the meta table of a table is the prototype of the table. In the object-oriented concept, it is the class of the table.

 

We can even write in this way:

 

A = {}

Setretriable (A,)

A. _ Index =

 

It works in terms of syntax principles. However, in order to avoid unnecessary troubles (loop definition), The Lua interpreter gave kick the problem. If it is written like this, an error is reported and a prompt is displayed.

 

Loop in gettable

 

To be honest, such a definition is useless.

 

The following introduces the implementation of object-oriented architecture.

 

First, let's reference the implementation snippets in Sputnik,

 

Local Sputnik = {}

Local Sputnik_mt ={__ resumable ={}, _ index = Sputnik}

 

Function new (config, logger)

 

-- After the obj object is generated here, the prototype of the obj is Sputnik, and there will be many Sputnik method definitions later.

Local obj = setmetatable ({}, Sputnik_mt)

-- The method here is the "inherited" Sputnik method.

Obj: init (config)

Returns the reference of this object.

Return obj

End

 

As shown in the preceding figure, a method is added to the two table definitions to implement classes and solutions for generating objects by classes. Because this is in the module, there is no table name before new. This method has the advantage of using

 

Sputnik = require "sputnik"

Then, call

S = sputnik. new ()

You can generate a sputnik object s, which inherits all the methods and attributes of the prototype Sputnik (that is, the table defined above.

 

However, it is also a problem to define this method, that is, it is inconvenient to implement the inheritance of classes. It is easy to define classes and generate objects, but it is not convenient to inherit between classes.

 

The following is implemented in another way.

 

A = {

X = 10,

Y = 20

}

 

Function A: New (t)

Local T = T or {}

Self. _ Index = self

Setretriable (T, self)

Return t

End

 

Generate an object AA from

 

AA = A: New ()

 

AA is a new table, which is an object but a class. It can continue with the following operations:

 

S = AA: New ()

 

Aa does not have the new method, but it is assigned a meta table (also a prototype). At this time, a has two fields: New Method and X and Y.

 

AA uses _ index to trace back to a to find the new method, execute the new code, and pass in the self parameter. This is amazing. At this time, the Passed Self parameter references the AA table, instead of the table for the first call. Therefore, AA: After new () is executed, a new object S is generated. The object is prototype AA and inherits all the content of AA. So far, have we implemented class inheritance? AA is now a subclass of A, and s is an object instance of AA. You can also create a long inheritance chain by analogy.

 

It can also be seen that the concept of a class is different from that of a prototype. Lua is a prototype language, which is obviously a prototype of a class, the prototype is just a regular object.

 

Below, if the function is defined in:

Function A: ACC (V)

Self. x = self. x + V

End

 

Function A: Dec (V)

If v> self. X then error "not more than zero" End

Self. x = self. X-V

End

 

Then, call

S: ACC (5)

 

Then, we call this method in this way. First, we can find the ACC method in S, but we cannot find the ACC method in AA, find this method in A and find it. After finding it, pass the self parameter pointing to S and the 5 parameter into the ACC function, and execute the ACC code. When executing the code in it, this sentence:

Self. x = self. x + V

On the right side of the expression, self. X is a null value, because self points to S. Therefore, we always find an X in A according to _ index, and then reference this X value, 10. Therefore, the above expression becomes

Self. x = 10 + 5

Calculate 15 on the right and assign the value to the left, but then self. X is not defined, but the _ newindex meta method is not defined in s (and the meta-table of S). Therefore, in self (s) create an X field in the table to be pointed to, and assign 15 values to this field.

 

After this operation, there is a field (member variable) x in instance s, and its value is 15.

Next time, if you call

S: Dec (10)

In this case, a similar backtracking operation will be performed, but only method Backtracking will be performed this time, instead of member variable X backtracking, because the member variable X already exists in S, after this function is executed, S. X is equal to 5.

 

In summary, this is the process of class inheritance and object instance method reference. However, the words have not been completed yet.

 

Aa can be used as a subclass of A, because classes and objects under AA will first pass through it when searching, so it can reload the method of A. For example, it can define the following function:

 

Function AA: ACC (V)

...

End

 

Function AA: Dec (V)

...

End

 

Functions can write new and different content to cope with complex differences in the real world. This feature is object-oriented, that is, subclasses can overwrite the methods of the parent class and member variables (fields), that is, overloading. This feature is required.

 

You can also define some methods and fields not in A in AA. The operations are the same.

 

Objects in Lua also have a flexible and powerful feature, that is, they do not need to create a new class to specify a new behavior. If only one object requires a special behavior, you can implement this behavior directly in the object. That is to say, after an object is created, the methods and fields of the object can be added and reloaded to cope with actual changes. Without modifying the definition of the driver category. This is also the benefit of class as a common object. More flexible.

 

We can see that the: new () function is A key function and plays A key factor in class inheritance. However, to adapt to the usage in the module (many),

Function new (t)

A: new (t)

End

Encapsulate the generated function. Then, you only need to use the module name. new () to generate an instance object A outside the module.

 

We can see how self-consistent, concise, flexible, and powerful this type of implementation mechanism is! But it's time to torture your brain.

 

From: http://blog.csdn.net/xenyinzen/archive/2008/12/17/3536708.aspx

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.