Hacker News new | ask | show | jobs
by createuniverses 4249 days ago
I've wrangled a crazy way to have your cake and eat it too.

  do
    local state = 0
    function render()
      drawLine(0,5,0, 0,5,50*math.sin(state))
      state = state + math.pi * 0.03
    end
  end
To fiddle with the "state" variable from the outside:

  name,val = debug.getupvalue(render, 1)
  print(name) -- state
  print(val)  -- state's value

  debug.setupvalue(render, 1, 0) -- set state to 0
To find out how many upvalues are available:

  dt = debug.getinfo(render)
  print(dt.nups)
If you want to redefine render without disturbing state, you need to backup state and make a new closure with the new definition of render and the restored state:

  do
    local savedstate = {debug.getupvalue(render,1)}
    local state = savedstate[2]
    function render()
      local h = 5
      drawLine(0,h,0,50 * math.sin(state), h,0)
      state = state + math.pi * 0.06
    end
  end
I don't think its possible (or I don't know how) to redefine a function inside a closure. So just make a new closure and restore its state.
1 comments

Well, there are many hacks around it; see the immediate-mode programming frameworks like Sol. My own personal take on this problem is to make "refresh" a first-class part of the programming model (rather than something managed by the programmer), and then to define encapsulated state that is preserved on refresh (by the programming model). You can read about it in my paper. (http://research.microsoft.com/apps/pubs/default.aspx?id=2112...)

The trick is to generate stable IDs to represent the state, then you can think of it as a global map:

    var map = new Map()
    
    def render():
      var x = map[0x138293]
      ...
      map[0x13244] = y
This resembles your last solution above. The trick is then automatically reproducing those IDs when render is called again (not to mention tearing down any side effects no longer performed, but that is another kettle of fish).