--[[ Exploring Languages with Interpreters and Functional Programming Copyright (C) 2018, H. Conrad Cunningham Lua prototype-based programming Counting example from Chapter 3 1234567890123456789012345678901234567890123456789012345678901234567890 2018-08-23: CountingPB:new() adapted from Prototype:new() method in 2018-11-02 module Prototype.lua (Prototype Delegation and Cloning with Mixins module) CountingPB is a Lua module. When imported with a "require" call, it returns a Lua module table (i.e. an object). This table is the top-level "prototype object" for the CountingPB application. The prototype object has the default method definitions. The following call of the constructor "new" with the given "mixin" object (i.e. table) (assuming local variable CountingPB holds the prototype object) x = CountingPB:new({count = 0, maxc = 10 }) creates a "clone" object "x" of CountingPB with its own instance variables "count" and "maxc" but delegates method calls back to object CountingPB. (We can use the same general technique to implement "class objects" for a more traditional object-oriented structure.) However, object "x" itself can be used to create a new clone "y". The code y = x:new({ count = 10, maxc = 15 }) creates a new object y that has different state than x but delegates method calls to x, which, in turn, delegates them on to CountingPB. (If count or maxc are not given new non-nil values, then acceses to them also delegate back to object x.) But the constructor "new" can also substitute in new definitions of the hook methods "has_more" and "adv". It could also add new methods and data attributes, such as "by" and "msg" below. It can change maxc but allow count to be used from the receiver object. z = y:new( { maxc = 400, has_more = function (self,c,m) return c ~= 0 and math.abs(c) <= math.abs(m) end, adv = function(self) self.count = self.count * 2 end, bye = function(self) print(self.msg) end msg = "Good-Bye!" } ) Instead of incrementing by 1 as in the original "adv", this method doubles the value of the "count" argument on each call. --]] local CountingPB = {count = 1, maxc = 0} function CountingPB:new(mixin) mixin = mixin or {} local obj = { __index = self } for k, v in pairs(mixin) do if k ~= "__index" then obj[k] = v end end return setmetatable(obj,obj) end function CountingPB:has_more(c,m) return c <= m end function CountingPB:adv() self.count = self.count + 1 end function CountingPB:counter() while self:has_more(self.count,self.maxc) do print(self.count) self:adv() end end return CountingPB