Non-lexical (lexical) scoping

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

Non-lexical (lexical) scoping

Soni "They/Them" L.
Let's talk about non-lexical lexical scopings. That is, the ability to
undefine variables.

That ability is itself lexically scoped, ofc.

E.g.

a = 2
local a = 1
do
   forget a
   print(a) assert(a == 2)
end
print(a) assert(a == 1)

This also applies to upvalues:

do
   a = 0
   local a, a, a = 1, 2, 3
   function f()
     assert(a == 3)
     forget a
     assert(a == 2)
     do
       forget a
       assert(a == 1)
       forget a
       assert(a == 0)
     end
     assert(a == 2)
   end
   assert(a == 3)
   f()
   assert(a == 3)
end
f()

So, non-lexical scoping doesn't forget the *values*, but the
variables/bindings.

I think this sounds neat. What do you think?

--
Disclaimer: these emails may be made public at any given time, with or without reason. If you don't agree with this, DO NOT REPLY.


Reply | Threaded
Open this post in threaded view
|

Re: Non-lexical (lexical) scoping

Dirk Laurie-2
2018-03-20 0:38 GMT+02:00 Soni "They/Them" L. <[hidden email]>:
>
> Let's talk about non-lexical lexical scopings. That is, the ability to undefine variables.
,,,
>   forget a
...
>   local a, a, a = 1, 2, 3
This assumes something about implementation of multiple assignment
that Lua does not promise.
...
> I think this sounds neat. What do you think?

`forget a` looks evocative [1]. But `pop(a)` is the more usual word
for this sort of thing.

[1] https://xkcd.com/379/

Reply | Threaded
Open this post in threaded view
|

Re: Non-lexical (lexical) scoping

Soni "They/Them" L.


On 2018-03-20 01:57 AM, Dirk Laurie wrote:
> 2018-03-20 0:38 GMT+02:00 Soni "They/Them" L. <[hidden email]>:
>> Let's talk about non-lexical lexical scopings. That is, the ability to undefine variables.
> ,,,
>>    forget a
> ...
>>    local a, a, a = 1, 2, 3
> This assumes something about implementation of multiple assignment
> that Lua does not promise.
> ...

Those are 3 different locals.

local a, a, a = 1, 2, 3

*is*

local a = 1
local a = 2
local a = 3

(however, the order in which they are assigned is undefined [1])

But, this is different from

a, a, a = 1, 2, 3

Which is undefined, and could be any of:

a = 1
a = 2
a = 3

a = 3
a = 2
a = 1

a = 1
a = 3
a = 2

etc, you get the idea.

[1] - Using non-lexical scoping, local a, a, a = 1, 2, 3 could be
expanded to any of:

local a
local a
local a
do
   forget a
   forget a
   a = 1
end
do
   forget a
   a = 2
end
do
   a = 3
end

-- or

local a
local a
local a
do
   a = 3
end
do
   forget a
   a = 2
end
do
   forget a
   forget a
   a = 1
end

-- etc

They are still 3 locals, declared in order, with the 3 values also
declared in order.

>> I think this sounds neat. What do you think?
> `forget a` looks evocative [1]. But `pop(a)` is the more usual word
> for this sort of thing.
>
> [1] https://xkcd.com/379/
>

--
Disclaimer: these emails may be made public at any given time, with or without reason. If you don't agree with this, DO NOT REPLY.


Reply | Threaded
Open this post in threaded view
|

Re: Non-lexical (lexical) scoping

Soni "They/Them" L.


On 2018-03-20 02:09 AM, Soni "They/Them" L. wrote:

>
>
> On 2018-03-20 01:57 AM, Dirk Laurie wrote:
>> 2018-03-20 0:38 GMT+02:00 Soni "They/Them" L. <[hidden email]>:
>>> Let's talk about non-lexical lexical scopings. That is, the ability
>>> to undefine variables.
>> ,,,
>>>    forget a
>> ...
>>>    local a, a, a = 1, 2, 3
>> This assumes something about implementation of multiple assignment
>> that Lua does not promise.
>> ...
>
> Those are 3 different locals.
>
> local a, a, a = 1, 2, 3
>
> *is*
>
> local a = 1
> local a = 2
> local a = 3
>
> (however, the order in which they are assigned is undefined [1])
>
> But, this is different from
>
> a, a, a = 1, 2, 3
>
> Which is undefined, and could be any of:
>
> a = 1
> a = 2
> a = 3
>
> a = 3
> a = 2
> a = 1
>
> a = 1
> a = 3
> a = 2
>
> etc, you get the idea.
>
> [1] - Using non-lexical scoping, local a, a, a = 1, 2, 3 could be
> expanded to any of:
>
> local a
> local a
> local a
> do
>   forget a
>   forget a
>   a = 1
> end
> do
>   forget a
>   a = 2
> end
> do
>   a = 3
> end
>
> -- or
>
> local a
> local a
> local a
> do
>   a = 3
> end
> do
>   forget a
>   a = 2
> end
> do
>   forget a
>   forget a
>   a = 1
> end
>
> -- etc
>
> They are still 3 locals, declared in order, with the 3 values also
> declared in order.


You can check this (local a, a, a = 1, 2, 3) with the debug library btw
- you'll see 3 separate locals.

You can check the global assignment stuff (a, a, a = 1, 2, 3) with
metatables/__newindex.

>
>>> I think this sounds neat. What do you think?
>> `forget a` looks evocative [1]. But `pop(a)` is the more usual word
>> for this sort of thing.
>>
>> [1] https://xkcd.com/379/
>>
>

--
Disclaimer: these emails may be made public at any given time, with or without reason. If you don't agree with this, DO NOT REPLY.


Reply | Threaded
Open this post in threaded view
|

Re: Non-lexical (lexical) scoping

Egor Skriptunoff-2
In reply to this post by Soni "They/Them" L.

On Tue, Mar 20, 2018 at 1:38 AM, Soni "They/Them" L. wrote:
the ability to undefine variables.
That ability is itself lexically scoped


Why the heck do you need this?
Show real-life example, please.
Reply | Threaded
Open this post in threaded view
|

Re: Non-lexical (lexical) scoping

Sean Conner
It was thus said that the Great Egor Skriptunoff once stated:
> On Tue, Mar 20, 2018 at 1:38 AM, Soni "They/Them" L. wrote:
>
> > the ability to undefine variables.
> > That ability is itself lexically scoped
> >
> >
> Why the heck do you need this?

  I have a few ideas:

        1) I just thought of this and I think it's a good idea.  Let me toss
           this out there and see if it sticks! [1]

        2) To get to upvalues that are masked by the same name:

                local a = 1
                function foo(x,y)
                  local a = 2
                  if x + y < 0 then
                    forget a -- get to the a that is equal to 1
                    return a
                  else
                    return x + y + a
                  end
                end

           Tis a silly example, but maybe gets the idea across.  Why anyone
           would *want* this I have no idea, since it assumes a particular
           stacking of scopes and I'm not aware of anyone anymore who thinks
           that dynamic scopes [2] is a good idea.

> Show real-life example, please.

  I'm curious as well.

  -spc

[1] I did this once, only it was for a feature in C that I used to do
        under Assembly.  Turned out to be a *very* bad idea---worse than
        setjmp()/longjmp() (which it was somewhat, kind of, similar to).

[2] Example of dynanmic scope, assuming Lua support it:

                        x = 1

                        local function foo()
                          print(x)
                        end

                        local function bar()
                          local x = 2
                          foo()
                        end

                        foo()
                        1
                        bar()
                        2

        foo() will use the first x it finds along the call chain, so when
        bar() calls foo(), foo() will see the x in bar and print it.

        This is a *bad* idea.  It's one of the few bad ideas from Lisp.  It
        makes debugging in a large codebase more difficult.

Reply | Threaded
Open this post in threaded view
|

Re: Non-lexical (lexical) scoping

Soni "They/Them" L.


On 2018-03-20 03:37 AM, Sean Conner wrote:

> It was thus said that the Great Egor Skriptunoff once stated:
>> On Tue, Mar 20, 2018 at 1:38 AM, Soni "They/Them" L. wrote:
>>
>>> the ability to undefine variables.
>>> That ability is itself lexically scoped
>>>
>>>
>> Why the heck do you need this?
>    I have a few ideas:
>
> 1) I just thought of this and I think it's a good idea.  Let me toss
>   this out there and see if it sticks! [1]
>
> 2) To get to upvalues that are masked by the same name:
>
> local a = 1
> function foo(x,y)
>  local a = 2
>  if x + y < 0 then
>    forget a -- get to the a that is equal to 1
>    return a
>  else
>    return x + y + a
>  end
> end
>
>   Tis a silly example, but maybe gets the idea across.  Why anyone
>   would *want* this I have no idea, since it assumes a particular
>   stacking of scopes and I'm not aware of anyone anymore who thinks
>   that dynamic scopes [2] is a good idea.
>
>> Show real-life example, please.
>    I'm curious as well.

It's most useful in languages with strong brorrowck, like Rust. For example:

let mut x = Some(1.0);
if let Some(ref mut v) = x {
   if cond {
     forget v; // without this, we would error "cannot use `x` because
it was mutably borrowed",
               // but since we are ending the scope of the borrow, we
can return x
     return x;
   }
   *v = 3.0;
}
// do some other stuff here

In Rust, there's a proposal for non-lexical lifetimes somewhere, altho
I'm not sure if it'd solve this particular case.

In Lua, the only use-case I can think of is for accessing shadowed
variables in a block scope:

function f(a, flag)
   local a = a or {}
   local b = true
   if flag then
     forget a -- temporarily forget the shadowed `a` so we can get to
the original `a`'s nil/false-ness
     b = not not a -- tobool operator
   end
   -- use the shadowed `a` normally
end

>
>    -spc
>
> [1] I did this once, only it was for a feature in C that I used to do
> under Assembly.  Turned out to be a *very* bad idea---worse than
> setjmp()/longjmp() (which it was somewhat, kind of, similar to).
>
> [2] Example of dynanmic scope, assuming Lua support it:
>
> x = 1
>
> local function foo()
>  print(x)
> end
>
> local function bar()
>  local x = 2
>  foo()
> end
>
> foo()
> 1
> bar()
> 2
>
> foo() will use the first x it finds along the call chain, so when
> bar() calls foo(), foo() will see the x in bar and print it.
>
> This is a *bad* idea.  It's one of the few bad ideas from Lisp.  It
> makes debugging in a large codebase more difficult.
>

Ew, no. I've been showing examples since this thread started.

--
Disclaimer: these emails may be made public at any given time, with or without reason. If you don't agree with this, DO NOT REPLY.


Reply | Threaded
Open this post in threaded view
|

Re: Non-lexical (lexical) scoping

Sean Bolton-2
In reply to this post by Egor Skriptunoff-2
On Tue Mar 20 2018, Egor Skriptunoff wrote:
> On Tue, Mar 20, 2018 at 1:38 AM, Soni "They/Them" L. wrote:
>
> > the ability to undefine variables.
> > That ability is itself lexically scoped
> >
> Why the heck do you need this?
> Show real-life example, please.

I think it's an attempt to catch up to JavaScript. For example,
'this' with 'call', 'bind', 'apply', and '=>' in various scopes.
We can't have Lua falling behind in confusingness!

Sorry, Soni, I admire your curiosity and inventiveness, but I just
couldn't resist teasing.

-Sean

Reply | Threaded
Open this post in threaded view
|

Re: Non-lexical (lexical) scoping

dyngeccetor8
In reply to this post by Soni "They/Them" L.
On 03/20/2018 02:57 PM, Soni "They/Them" L. wrote:

>
> In Lua, the only use-case I can think of is for accessing shadowed variables in
> a block scope:
>
> function f(a, flag)
>   local a = a or {}
>   local b = true
>   if flag then
>     forget a -- temporarily forget the shadowed `a` so we can get to the
> original `a`'s nil/false-ness
>     b = not not a -- tobool operator
>   end
>   -- use the shadowed `a` normally
> end

I think better way is to allow indirect access to lexical scope
variables. Like "_G" but populated with local variables. (And
some awkward name to access outer level, say "__parent".)

So you code example becomes

  function f(a, flag)
    local a = a or {}
    local b = true
    if flag then
      b = not not _ENV.__parent.a -- tobool operator
    end
    -- use the shadowed `a` normally
  end

I believe this may be implemented but will introduce much more
problems than solve.

-- Martin

Reply | Threaded
Open this post in threaded view
|

Re: Non-lexical (lexical) scoping

Soni "They/Them" L.


On 2018-03-20 07:15 PM, dyngeccetor8 wrote:

> On 03/20/2018 02:57 PM, Soni "They/Them" L. wrote:
>> In Lua, the only use-case I can think of is for accessing shadowed variables in
>> a block scope:
>>
>> function f(a, flag)
>>    local a = a or {}
>>    local b = true
>>    if flag then
>>      forget a -- temporarily forget the shadowed `a` so we can get to the
>> original `a`'s nil/false-ness
>>      b = not not a -- tobool operator
>>    end
>>    -- use the shadowed `a` normally
>> end
> I think better way is to allow indirect access to lexical scope
> variables. Like "_G" but populated with local variables. (And
> some awkward name to access outer level, say "__parent".)
>
> So you code example becomes
>
>    function f(a, flag)
>      local a = a or {}
>      local b = true
>      if flag then
>        b = not not _ENV.__parent.a -- tobool operator
>      end
>      -- use the shadowed `a` normally
>    end
>
> I believe this may be implemented but will introduce much more
> problems than solve.

Bleh.

Idk, I've touched the Lua internals before. I'd say "forget" is much
easier on the register (de)allocator stuff.

>
> -- Martin
>

--
Disclaimer: these emails may be made public at any given time, with or without reason. If you don't agree with this, DO NOT REPLY.


Reply | Threaded
Open this post in threaded view
|

Re: Non-lexical (lexical) scoping

Dirk Laurie-2
In reply to this post by dyngeccetor8
2018-03-21 0:15 GMT+02:00 dyngeccetor8 <[hidden email]>:

> On 03/20/2018 02:57 PM, Soni "They/Them" L. wrote:
>>
>> In Lua, the only use-case I can think of is for accessing shadowed variables in
>> a block scope:
>>
>> function f(a, flag)
>>   local a = a or {}
>>   local b = true
>>   if flag then
>>     forget a -- temporarily forget the shadowed `a` so we can get to the
>> original `a`'s nil/false-ness
>>     b = not not a -- tobool operator
>>   end
>>   -- use the shadowed `a` normally
>> end
>
> I think better way is to allow indirect access to lexical scope
> variables. Like "_G" but populated with local variables. (And
> some awkward name to access outer level, say "__parent".)

If the code is not stripped, the debug library has the necessary information.

The more I think about this idea, the more it seems to me that

(a) the same functionality is achievable already, in a cumbersome way,
 in "pure" Lua 5.1
(b) such simple syntax would allow the effortless writing of programs
with really opaque logic

So I agree with Martin's conclusion:

> I believe this may be implemented but will introduce much more problems than solve.