lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


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-----
>