lua-users home
lua-l archive

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


Responding to a private message (sender suppressed) with some public comments...

> On Sat, 23 Jan 2010 17:21:51 -0800
> Mark Hamburg <mark@grubmah.com> wrote:
> 
>> It is, however, an attempt to figure out why so many people look at in-do-end and expect...
> 
> Well, for your collection, at first sight I had yet another interpretation:
> 
> local t
> in t do
>  a = 2
>  b = mat.pow(a,3)
> end
> should let t = {a=2, b=8},
> Meaning in...do was an idiom for a kind of "executable" table constructor, or mofifier. (Realise now it's close to Pascal's with.)


I'm assuming the omission of t = { } was an e-mail coding error.

The Pascal WITH statement is the other obvious model. The difference in semantics is that in-do-end gets rid of access to globals which potentially undermines the ability to write math.pow (unless you first capture math in a local). I'm not sure of the difference in suggested semantics between "in" and "with" though the latter seems to have more of an "in addition" or object manipulation feel to it while the former seems more to be about setting context.

Note that this is a case where pushenv would be useful with the 5.2 semantics as well as dynamic semantics:

	local t = {}
	in pushenv( t ) do
		a = 2
		b = math.pow( a, 3 ) -- works because of pushenv
	end

The simplistic 5.2 definition of pushenv is (I think):

	function pushenv( newenv )
		local oldenv = getfenv( 1 ) -- However one gains access to it...
		return setmetatable( { }, {
			__newindex = newenv, -- Assignments go to newenv
			__index = function( t, k )
				local result = newenv[ k ]
				if result ~= nil then return result end -- or won't work because we need to support newenv[ k ] == false
				return oldenv[ k ]
			end
		} )
	end

Note, however, that given the actual semantics of in-do-end, this will not work with nested use of in-do-end because the actual function environment fetched above by any of the proposed implementations for getfenv is not redefined by in-do-end. So, we actually need something more like the following:

	local function pushenv_helper( oldenv, newenv )
		local resultenv = { }
		resultenv.pushenv = function( t ) return pushenv_helper( resultenv, t ) end
		setemetatable( resultenv, {
			__newindex = newenv, -- Assignments go to newenv
			__index = function( t, k )
				local result = newenv[ k ]
				if result ~= nil then return result end
				return oldenv[ k ]
			end
		} )
		return resultenv
	end

And we initialize the global state with:

	_G.pushenv = function( t ) return pushenv_helper( _G, t ) end

Mark