undo previous commit

[?]
Apr 16, 2023, 12:23 AM
D27H6QACP3CH27QHVRTYAQPOQGJH37AK56URJXQJLZVSMHIFX4NQC

Dependencies

  • [2] H3RX6UWR abortive experiment: keep definitions independent
  • [3] BSDXVB3H backport some doc updates and renames
  • [4] 3BRGOF7N return failing tests with every code change
  • [5] UY647VAQ rename
  • [6] WYKKFV2G prevent overriding foundational definitions
  • [7] FFFJ54GJ restore globals after running tests
  • [8] LRDM35CE app running again
  • [9] QFURHRTP rename globals to have a single uppercase letter
  • [10] NVEA3SMU reorg

Change contents

  • edit in live.lua at line 39
    [3.53][2.12:48]()
    Live.initial_env = table.copy(_G)
  • edit in live.lua at line 260
    [3.637][2.49:66]()
    -- pre-check
  • edit in live.lua at line 264
    [3.1415][2.67:132]()
    -- perform the real evaluation and send back any real errors
  • edit in live.lua at line 276
    [3.30][2.133:3160]()
    -- 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 364
    [3.1251][2.3161:3446]()
    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 366
    [3.1256][2.3447:3559]()
    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 367
    [3.1257][2.3560:3676]()
    function table.length(h)
    local result = 0
    for _ in pairs(h) do
    result = result+1
    end
    return result
    end