Presentation is loading. Please wait.

Presentation is loading. Please wait.

References: 1. “Programming in LUA, 2 nd ed.”, Roberto Lerusalmschy Chapters 13+16 (primarily) 2. “Lua Reference Manual” (included in Lua installation.

Similar presentations


Presentation on theme: "References: 1. “Programming in LUA, 2 nd ed.”, Roberto Lerusalmschy Chapters 13+16 (primarily) 2. “Lua Reference Manual” (included in Lua installation."— Presentation transcript:

1 References: 1. “Programming in LUA, 2 nd ed.”, Roberto Lerusalmschy Chapters 13+16 (primarily) 2. “Lua Reference Manual” (included in Lua installation or online)

2 Overview  Lua doesn't have a separate OOP facility.  It does have means to "coerce" tables into classes. Not as pretty as python… We'll need to look at Metatables (ch. 13)  We'll also look at (the hard way of) creating modules Why the hard way? A: It's how we'll have to do it in ssuge.

3 Normal "missing" behavior  If Lua can't find a variable, it returns nil A global variable A member of a table [sample2_01.lua] x = 10 a = {x = 13, y = 15} print(x) -- 10 print(a.x) -- 13 print(a["x"])-- 13 print(y) -- nil print(a.y) -- 15 print(a.z) -- nil print(a["z"])-- nil

4 Functions and Tables  Functions are "first-class" citizens in Lua.  You can store them in variables. Normal variables or table entries. [Sample2_01.lua, cont.] function foo(test) print("Hello! You gave me '".. test.. "'") end bar = foo foo("blah") -- “Hello! You gave me ‘blah’” bar("argh") -- “Hello! You game me ‘argh’” a.func_member = foo a.func_member("joust!") --or... a = {x = 13, y = 15, func_member = function() -- (as before – end } a.func_member("yow") -- “Hello! You gave me ‘yow’”

5 MetaTables  A metatable is: A normal Lua table Can be set as the metatable for another table (or sometimes itself, oddly enough…) ○ getmetatable(tab) ○ setmetatable(tab, meta_tab) Can contain metamethods (which sometimes can be implemented as tables) ○ __index is a special one: Called when a requested key is missing Can be a table or a function (with the table and key as parameters)

6 MetaTables (and __index) example (sample2_02.lua) a = {x = 9, y = 13, z = 15} print(a.x) -- 9 print(a.w) -- nil print(getmetatable(a)) -- nil m = {} -- going to be a metatable m.__index = {w = 1000, q = 20000} setmetatable(a, m) print(m) -- table: 0042EE08 print(getmetatable(a)) -- table: 0042EE08 print(a.x) -- 9 print(a.w) -- 1000 print(a.q) -- 20000 print(a.b) -- nil print(rawget(a, "x")) -- 9 print(rawget(a, "w")) -- nil ( Bypasses __index ) m.__index = function(tab, key) if key == "w" then return 1000 else if key == "q" then return 20000 end

7 Other "meta-methods" m.__add = function(t1, t2) if getmetatable(t1) ~= getmetatable(t2) then error("You can only call this method with two m-based tabls") end r = {} -- a new instance setmetatable(r, getmetatable(t1)) -- make result of same "type" as t1 for k, v in pairs(t1) do if t2[k] ~= nil then r[k] = t1[k] + t2[k] end return r end a = {x = 5, y = 9, z = 2} b = {x = 15, z = 3} setmetatable(a, m) setmetatable(b, m) c = a + b -- c is now {x = 20, z = 5} (with a metatable of m)

8 Other "meta-methods", cont. m.__tostring = function(t1) s = "[m-table| " -- Count number of key-value pairs in t1 num_elem = 0 for k, v in pairs(t1) do num_elem = num_elem + 1 end -- Append elements to s count = 0 for k, v in pairs(t1) do if count < num_elem - 1 then s = s.. v.. ", " else s = s.. v.. "]" end count = count + 1 end return s end a = {x = 15, y = 3, z = 5} setmetatable(a, m) print(a) -- [m-table| 15, 3, 5] (indirectly calls __tostring) x = tostring(a) -- x now holds “[m-table| 15, 3, 5]”

9 OOP in Lua  We've actually already been using Lua's "OOP" facilities. Instances are tables We create another table (the class) and set the metatable of the instances.  My example's pretty much that of the book's (Ch. 16)

10 OOP Example, part I/3 -- The "Class" definition Account = {balance = 0} -- A normal table. It's *going* to be the -- default attribute values for instances of the -- Account "class" function Account:withdraw(amt) self.balance = self.balance - amt end -- Alternate syntax #1 -- function Account.withdraw(self, amt) -- self.balance = self.balance – amt -- end -- Alternate syntax #2 -- Account = { balance = 0, -- function withdraw(self, amt) -- self.balance = self.balance – amt -- end -- }

11 OOP Example, part 2/3 -- The “constructor" function function Account:new(initialTable) -- self (in this context) is the Account class. -- Our job is to make a new table (the new object) -- of "class" Account. o = initialTable or {} -- sets o to a new table if nil is passed. setmetatable(o, self) -- Makes Account the metatable for o. self.__index = self -- Note: confusing! We just set o's metatable to -- be Account. If we define an __index method, -- o will look for any missing methods / keys in -- Account. This will also (later) play a role -- in inheritance. return o end -- like “__str__” in python. function Account:__tostring() return "[Account: balance=".. self.balance.. "]" end

12 OOP Example, part 3/3 -- Creating instances a = Account:new({balance=1000}) -- a = Account.new(Account, {balance=1000}) (alternate syntax) print(a) -- [Account: balance=1000] a:withdraw(200) print(a) -- [Account: balance=800] b = Account:new() -- passes nil for initialTable (so no values in table) b.balance = 200 -- does a lookup in Account.__index. Gets the value 0 and -- assigns to a *new* variable in b's table. That'll be used -- for b's balance in the future (Account.balance won't change) b:withdraw(100) print(a) -- [Account: balance=800] (making b didn’t change a) print(b) -- [Account: balance=100]

13 Inheritance  Just a (clever / obfuscated) use of metatables and it's __index field. SpecialAccount = Account:new({limit=1000.0}) -- SpecialAccount is (for now) -- an instance of Account with a new field print(SpecialAccount) -- [Account: balance=0] s = SpecialAccount:new() -- Special Account doesn't have a new method. So... -- Lua looks in the metatable's __index table (which is -- Account) and calls its new method. Here’s the trick: -- self (in Account:new) is now SpecialAccount. So -- we’re setting __index calls to point there. But... -- if it doesn’t have that value, it uses its __index -- method (which points to Account). print(s) -- Interesting quirk: SpecialAccount doesn't have an __index method -- in it's metatable, so Lua defaults to the default-table output. -- it’s doing -- It doesn't dig deep enough. The easy solution... SpecialAccount.__tostring = Account.__tostring print(s) -- [Account: balance = 0]

14 Inheritance, cont. -- We can add methods to SpecialAccount just like any “class” function SpecialAccount:getLimit() if self.limit == nil then return 0 else return self.limit end

15 Inheritance and "polymorphism" -- If we add methods to SpecialAccount (which have the same name -- as one in Account), they will be used instead of Account's function SpecialAccount:withdraw(amt) if amt > self:getLimit() + self.balance then error("Insufficient funds!") else self.balance = self.balance - amt -- allow a (possibly) negative amt end t = SpecialAccount:new() u = SpecialAccount:new({balance = 150, limit = 900}) --t:withdraw(100) -- Would trigger the error u:withdraw(1000) print(u) -- [Account: balance=-850]

16 Modules in Lua  A module is a table returned by the require statement  Lua (and the OS) search according to LUA_PATH environment variable ?;?.lua;c:\windows\?;/usr/local/lua/?/?.lua The “?” are replaced with “my_module” (here)  All non-local “things” in the module are packaged into a table. -- This is on the “user” side local foo = require “my_module” -- foo contains one function called bar. x = foo.bar()

17 Modules, cont.  There is a global variable package in Lua. package.path is the $PATH variable package.cpath is dll locations … package.loaded is all loaded modules  When you use require the first time it adds to package.loaded. All future references to that module go through package.loaded (much faster).

18 Modules, cont.  Finally, Lua keeps one more global variable, _G, which stores a reference to things in package.loaded also stores a reference to all global variables

19 Creating modules (the “disciplined” method) -- In “foo.lua” -- Part I: Create the module local modname =... --... is the name of this file (require is -- passing it to us as an argument) local M = {} -- Create a new table (the module) _G[modname] = M -- insert M into _G package.loaded[modname] = M -- insert M into package.loaded -- Part II: Make local references to any external “things” local sqrt = math.sqrt local table = table -- Part III: Freeze all external access (so we don’t clutter _G) setfenv(1, M) -- Changes our environment (the 1 indicates -- we’re changing this module’s environment. -- 2 would be the importer, 3 would be their -- importer, etc. -- Part IV: Write the module -- Anything we create here will go into M (and so the user will be able -- to do “foo.xyz” to access it). Note: If a normal Lua “thing” isn’t -- declared in part II, it will come back as a nil reference.


Download ppt "References: 1. “Programming in LUA, 2 nd ed.”, Roberto Lerusalmschy Chapters 13+16 (primarily) 2. “Lua Reference Manual” (included in Lua installation."

Similar presentations


Ads by Google