1) Let's trace the history of object oriented languages back to Simula 67? Simula 67 / \ / \ Smalltalk Self / | | / perl JavaScript C++ python ActionScript java php5.0 Lua C# etc etc etc 2) What is the main particularity of each branch in this tree? 3) Has anyone heard about Lua? 4) Lua is a scripting dynamic language. What are the main characteristics of dynamic language? - Dynamic interpretation: eval, loadstring, etc - Dynamic typing. 4.2) Any other characteristics? - Garbage collection. - Reflexivity. 5) Of course, there is a continuum between dynamic and static languages. Java is much more dynamic than C. How to see this? 6) In addition of been a dynamic language, Lua is also a scripting language. What is a scripting language? 7) How do we install Lua? - Windows: LfW - Linux: lua5.1 - MacOs: port install lua 8) How do we start the interpreter? $> lua 9) What does this program do? > print(2^0.5) 10) And this program? function add (a) local sum = 0 for i = 1, #a do sum = sum + a[i] end return sum end print (add {1,2,3}) 10.1) What is the meaning of the keywords in the program above? 10.2) Why do we need parentheses in print (...), but we do not need parentheses in add ...? 11) What does this program do? function addfile (filename) local sum = 0 for line in io.lines(filename) do sum = sum + line -- sum = sum + tonumber(line) end return sum end print (addfile "f1.txt") 12) Functions, in Lua, are first class values. What is this? 12.1) For instance, what this program is doing? > (function (a,b) print(a+b) end)(10, 20) 12.2) The function "disappears" right after we use it, and there is no way to recover it. How can we re-use a function then? > foo = function (a,b) print(a+b) end > foo(10, 20) -- or -- > function foo (a, b) print(a + b) end 12.3) The last clause is just a syntactic sugar. What is a syntactic sugar? 13) Functions in Lua can return multiple values. For instance, what the program below is doing? > function foo(x) return x, x+1 end > a, b = foo(10) 13.1) How to get this functionality in languages that do not offer the multiple return syntax? 14) What does the program below does? function prefixes (s, len) len = len or 0 if len <= #s then return string.sub(s, 1, len), prefixes(s, len + 1) end end > print(prefixes("alo")) --> a al alo 14) In Lua, code traces are also first class values. What does this example do? > i = 0 > f = loadstring("print(i); i = i + 1") > f() > f() 14.1) How could I implement the same functionality using functions? > g = function() print(i); i = i + 1 end > g() > g() 14.2) Could I do the same in C or Java? * Dynamic code evaluation is one of the main characteristics of dynamic languages. 15) What will be printed? > g = function() print(i); i = i + 1 end > print(g) 15.1) And what will be printed? f = loadstring("function foo (x) print(10*x) end") print(foo) f() print(foo) foo(10) * The basic data-structure of lua is the table. Tables are used for everything: arrays, records, lists, objects and modules. 16) What is the use of the '.' below? t = {} t["x"] = 10; t.y = 20; print(t.x, t["y"]) 17) What does the program below do? function bt (init, stop, step, assign) local t = {} for i = init, stop, step do t[i] = assign(i) end return t end 18) How to implement a program that sorts the words in a file by the order of frequency? local t = io.read("*all") local count = {} for w in string.gmatch(t, "%w+") do count[w] = (count[w] or 0) + 1 end local words = {} for w in pairs(count) do words[#words + 1] = w end table.sort(words, function (a,b) return count[a] > count[b] end) for i=1, (arg[1] or 10) do print(words[i], count[words[i]]) end 18.1) How to execute the program above? $> lua cf.lua < l1.lua 19) What is a module? I mean, a program module? 20) How to build modules in lua? vector = {} vector["norm1"] = function (x, y) return (x^2 + y^2)^(1/2) end vector["norm2"] = function (x, y) return math.abs(x) + math.abs(y) end print(vector["norm1"](2.3, 4.1)) print(vector["norm2"](2.3, 4.1)) 21) Notice that t["f"] can be written as t.f. How to use this syntactic sugar to improve the program above? vector = {} vector.norm1 = function (x, y) return (x^2 + y^2)^(1/2) end vector.norm2 = function (x, y) return math.abs(x) + math.abs(y) end print(vector.norm1(2.3, 4.1)) print(vector.norm2(2.3, 4.1)) 22) Very good. Yet, lua gives you table constructors. For instance, you can initialize a table like: t = {s1 = e1, s2 = e2, ..., sn = en}. How to use constructors to improve the readability of the program above once more? vector = { norm1 = function (x, y) return (x^2 + y^2)^(1/2) end, norm2 = function (x, y) return math.abs(x) + math.abs(y) end } print(vector.norm1(2.3, 4.1)) print(vector.norm2(2.3, 4.1)) 23) Notice that here a table is used as a name space. What is a name space? 24) A table like vector is almost an object, yet it looks more like a utility class. How can we create something more like an object? Rect = { x = 0, y = 0, width = 10, height = 20, area = function() return Rect.width * Rect.height end } > dofile "r1.lua" > print (Rect.area()) 20 > Rect.width = 100 2000 > print (Rect.area()) 25) But now we have a singleton. What is again a sigleton? 26) How can we create more instances of Rectangle? Rect = { x = 0, y = 0, width = 10, height = 20, area = function() return Rect.width * Rect.height end, clone = function() o = {}; o.x = Rect.x; o.y = Rect.y; o.width = Rect.width; o.height = Rect.height; o.area = Rect.area; return o end } 27) But that is not very good: > r1 = Rect.clone() > print(r1.area()) 200 > r1.width = 40 > print(r1.width) 40 > print(Rect.width) 10 > print(Rect.area()) 200 > print(r1.area()) 200 28) You see, Rect and r1 share the same function area. How can we change this? Rect = { x = 0, y = 0, width = 10, height = 20, area = function(self) return self.width * self.height end, clone = function(self) o = {}; o.x = self.x; o.y = self.y; o.width = self.width; o.height = self.height; o.area = self.area; return o end } > r1 = Rect.clone(Rect) > r1.width = 40 > print(r1.width) 40 > print(Rect.width) 10 > print(r1.area(r1)) 800 > print(Rect.area(Rect)) 200 30) Hum... having to pass the table to itself as a parameter looks rather ugly. Can we do something about it? > dofile "r3.lua" > print(Rect:area()) 200 > r2 = Rect:clone() > print(r2:area()) 200 > r2.width = 1 > print(r2:area()) 20 > print(Rect:area()) 200 31) The colon operator is a syntactic sugar for what? 32) Can we use it in the definition of functions? Rect = { x = 0, y = 0, width = 10, height = 20, } function Rect:area() return self.width * self.height end 33) How can we simulate inheritance in this kind of environment? A = {x = 10} B = {x = 20, y = 30} B.__index = B --> B is a metatable setmetatable(A, B) --> A delegates calls to B print(A.x, A.y) 34) Why can't we just make: A.__index = B? - Because in this case we would be just saying that A is a metatable, but we are not specifying any delegation. 35) In the end, how the rectangle class would look like? Rect = {x = 0, y = 0, width = 10, height = 20} Rect.__index = Rect function Rect:new (o) setmetatable(o, self) return o end function Rect:area () return self.width * self.height end r1 = Rect:new {width = 40, height = 60} print(r1:area()) r2 = Rect:new {} print(r2:area()) r1.width = 3 print(r1:area()) print(r2:area()) 36) Write a small function that has a "cache". That is, this function, memoizes the outcomes of other functions: function memoize(fn) local t = {} return function(x) local y = t[x] if y == nil then y = fn(x); t[x] = y end return y end end 37) Write the fibonacci function, so that fib(n) is the n-th term in the sequence of Fibonacci: function fib (n) if n == 1 or n == 2 then return 1 else return fib(n-1) + fib(n-2) end end 38) Use the dynamic code loading to take the time of some code sequence: function take_time(s) t1 = os.clock(); f = loadstring(s); f(); t2 = os.clock(); print("Time = " .. t2 - t1 .. " secs"); end 39) Take different time measurements for the fib function take_time("fib(31)") take_time("fib(32)") mf = memoize(fib) take_time("mf(31)") take_time("mf(31)") 40) Let's wrap it up: can you code our zoo hierarchy that we have been using as an example since forever? Animal = { name = "Animalia" } function Animal:eat() print ("(Animal) " .. self.name .. " is eating") end function Animal:new(o) o = o or {} setmetatable(o, self) self.__index = self return o end Mammal = Animal:new { name = "Mammalia" } function Mammal:eat() print ("(Mammal) " .. self.name .. " is eating") end function Mammal:suck() print ("(Mammal) " .. self.name .. " is sucking milk") end Dog = Mammal:new { name = "Canis lupus familiaris" } function Dog:eat() print ("(Dog) " .. self.name .. " is eating") end function Dog:bark() print ("(Dog) " .. self.name .. " is barking") end -- Working with the original object prototypes: print("Working with the original object prototypes"); Animal:eat(); Mammal:eat(); Dog:eat(); Mammal:suck(); Dog:suck(); Dog:bark(); -- Working with object instances: print("Working with object instances"); a = Animal:new {} m = Mammal:new {} d0 = Dog:new {} d1 = Dog:new {name = "Tigrinho"} a:eat(); m:eat(); d0:eat(); d1:eat(); m:suck(); d0:suck(); d0:bark(); d1:suck(); d1:bark();