[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Using environment for OO
- From: Eike Decker <zet23t@...>
- Date: Sat, 11 Apr 2009 00:34:56 +0200
Maybe I am wrong but ... isn't your constructor going to just going to
set function environments for the functions that are already set for
the object (none if the object is new) and that the class functions
are not going to have the object's scope but the class' scope only?
Also, the __newindex function is not going to cope with functions that
are replacing old ones since __newindex is only called if a new key is
inserted - changing existing ones can't be monitored with that
metafunction.
If you would want to have the functions having the object's scope, you
will need to change the function's environment when the function is
being called. A more transparent system could be to provide a function
that allows a function to set a table as its new environment, i.e.
function foo(self)
self.x = 21
setscope(self)
print(x) -- 21
end
This approach has the advantage that the function itself controls its
scoping - it doesn't depend on implementations of the underlaying OO
framework. It also provides a visual hint for readers that the scope
of this particular function is bound to an object. It involves less
"magically" operations that are triggered outside of the visual scope
of the programmer and it also allows programmers to decide if they
really want to use this way of programming that you suggest instead of
enforcing it. It is also compatible with the "default approach" for
implementing OO systems in Lua. I.e., you can also extend existing
code in the manner you want without changing the underlaying OO
mechanics of other modules you might use.
The scope function could also have instructions to disallow global
variable access and other stuff:
function foo (self) setscope(self) : globalscope "off" : readonly "on"
_G.print(x)
x = nil -- runtime error
end
Proove of concept code:
----
function setscope (obj)
local func = debug.getinfo(2,"f").func
local env = {}
local mt = {}
local readonly
function mt:__index(key)
if obj[key]~=nil then return obj[key] end
return _G[key]
end
function mt:__newindex(key,value)
assert(readonly~="on","attempt to write value in readonly mode")
obj[key] = value
end
setmetatable(env,mt)
setfenv(func,env)
local mod = {}
function mod:readonly(mode)
readonly = mode
return mod
end
return mod
end
account = {balance = 0}
function account:payin(money) setscope(self)
assert(money>0,"expected a payin")
balance = balance + money
end
function account:printbalance() setscope(self) : readonly "on"
print(balance)
balance = 0 -- error: attempt to write value in readonly mode
end
account:payin(100)
account:printbalance()
----
Eike
2009/4/10 Martin C. Martin <martin@martincmartin.com>:
> I want that to be transparent to the function definer, so my class object
> looks like this:
>
> MyClass = {
> __newindex = function (table, key, value)
> if type(value) == "function" then
> setfenv(value, table)
> end
> rawset(table, key, value)
> end
> }
>
> My "new" function takes a table to use for the object, so it goes through it
> an calls setfenv() on each function, like this:
>
> function MyClass.new(obj)
> obj = obj or {}
> for k, v in pairs(obj) do
> if type(v) == "function" then
> print ("Setting environment for ", k)
> setfenv(v, obj)
> end
> end
> setmetatable(obj, MyClass)
> MyClass.__index = MyClass
> return obj
> end
>
> For a class with no base class, I need to do this:
>
> setmetatable(MyClass, {__index = _G})
>
> Best,
> Martin
>
> David Given wrote:
>>
>> -----BEGIN PGP SIGNED MESSAGE-----
>> Hash: SHA1
>>
>> Martin C. Martin wrote:
>> [...]
>>>
>>> For an OO style while accessing fields is more common than globals, the
>>> environment option seems cleaner than the standard : option. Are there
>>> any down sides that I'm missing?
>>
>> Correct me if I'm wrong, but won't the same function (with one
>> environment) need to be shared among several different objects? Won't
>> you have to explicitly call setfenv() at the top of each method,
>> preventing them from being called reentrantly?
>>
>> - --
>> ┌─── dg@cowlark.com ───── http://www.cowlark.com ─────
>> │
>> │ "All power corrupts, but we need electricity." --- Diana Wynne Jones,
>> │ _Archer's Goon_
>> -----BEGIN PGP SIGNATURE-----
>> Version: GnuPG v1.4.9 (GNU/Linux)
>> Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
>>
>> iD8DBQFJ36h9f9E0noFvlzgRAhB3AKCll17SHhX4H985QHJIiWFGSKraKACgiIiU
>> UZuWXvTP18z81yD/xqMHK5o=
>> =OixL
>> -----END PGP SIGNATURE-----
>