abortive experiment: keep definitions independent

[?]
Apr 16, 2023, 12:22 AM
H3RX6UWRIBSSGIKCHCYBW2UMW63HLV77BULUXS3BIBKKBEOJ64EQC

Dependencies

Change contents

  • edit in live.lua at line 39
    [7.53]
    [6.1988]
    Live.initial_env = table.copy(_G)
  • edit in live.lua at line 261
    [3.637]
    [3.637]
    -- pre-check
  • edit in live.lua at line 266
    [7.1415]
    [3.832]
    -- perform the real evaluation and send back any real errors
  • edit in live.lua at line 279
    [8.30]
    [2.9]
    -- Try running in bare environment to catch any order-dependence in
    -- definitions. The basic intent is to avoid this situation:
    -- define X = 3
    -- define Y = X+1
    -- edit X = 4
    -- Now the definition of Y runs before X (because Freewheeling apps load
    -- top-level definitions in version order) when X is nil, and Y starts
    -- raising a confusing error. And all because we modified X. Action at a
    -- distance.
    --
    -- To avoid this we make sure each definition is always self-contained.
    --
    -- This feels highly experimental. Concerns:
    --
    -- 1. Any side-effects in top-level definitions will run twice. Ugh.
    -- But then, they will also run any time you restart the app.
    -- Putting side-effects in the top-level seems like a more unnatural thing
    -- for a programmer to do than defining one global in terms of another.
    --
    -- 2. We still won't catch situations where we depended on a global
    -- variable and it used to be non-nil but now it's nil:
    -- define X = 3
    -- define Y = X
    -- edit X = 4
    -- Now Y is nil when it didn't used to be. Which can be confusing. And it
    -- won't even raise any errors.
    --
    -- 3. I'm going to create only a shallow copy of globals. It's hard to
    -- think about what real, really humongous global variables we might end
    -- up accidentally copying and turning everything sluggish. We might still
    -- miss some situation like:
    -- define io.bar
    -- define Y = io.bar -- allowed because io.bar has leaked in to the bare environment
    -- So this isn't perfect.
    --
    -- 4. Lua's setfenv is confusing to me. I wonder if there's some situation
    -- like:
    -- X = foo()
    -- that might cause trouble because foo() will continue to use the
    -- non-initial environment.
    --
    -- So far it seems fine. My intent is only to catch order-dependence in
    -- top-level definitions. The initial environment will have a subset of
    -- definitions; we prevent the live app from mutating any of them. It seems
    -- reasonable to assume that any pre-existing functions will not rely on any
    -- globals some random app is going to introduce.
    --
    -- 5. I could probably move the setfenv into eval_in_initial_env, but that
    -- feels confusing to think about given the table of bar envs is itself
    -- stored in a global variable.
    --
    -- 6. I could probably avoid duplicating eval as eval_in_initial_env, but
    -- it feels less error-prone to keep the two isolated. We never mess with
    -- the env of the real eval.
    setfenv(live.eval_in_initial_env, table.copy(Live.initial_env))
    local status, err = live.eval_in_initial_env(buf)
    if not status then
    live.roll_back()
    live.send_to_driver('ERROR this definition depends on other globals which can lead to hard-to-debug errors. Please keep top-level definitions order-independent. Define functions for more complex initialization.')
    return
    end
  • edit in live.lua at line 428
    [4.1251]
    [4.1251]
    end
    -- exact copy of live.eval that has had setfenv applied to it
    function live.eval_in_initial_env(buf)
    local f = load('return '..buf, 'REPL')
    if f then
    return pcall(f)
    end
    local f, err = load(buf, 'REPL')
    if f then
    return pcall(f)
    else
    return nil, err
    end
  • edit in live.lua at line 444
    [4.1256]
    [4.1256]
    function table.copy(h)
    local result = {}
    for k,v in pairs(h) do
    result[k] = v
    end
    return result
    end
  • edit in live.lua at line 452
    [4.1257]
    [4.1257]
    function table.length(h)
    local result = 0
    for _ in pairs(h) do
    result = result+1
    end
    return result
    end