Arc Forumnew | comments | leaders | submitlogin
Variables accessible to all functions down a call stack
2 points by hasenj 4186 days ago | 4 comments
I wish there was a way to pass variables to functions "implicitly". As if by setting "global" variables, but without polluting the global scope.

    (= x 5)
    (def some-fn (name)
         (prn "Hello " name ", x = " x))

    arc> (w/config (x 10)
           (some-fn "There"))
    Hello There, x = 10
After w/config exits, x is set back to 5.

   arc>(some-fn "Here")
   Hello Here, x = 5
I could easily write a macro for that (in fact, I did write one). The problem is when we have multiple threads. I want w/config to only affect the current call stack. Call stacks running in other threads are by definition not part of the current call stack.

I think this kind of thing is called Dynamic Scoping[0]


3 points by akkartik 4186 days ago | link

Do racket's parameters (and aw's do what you want?


1 point by hasenj 4186 days ago | link

awesome, sounds like exactly what I'm asking for :D


1 point by evanrmurphy 4186 days ago | link to the rescue again! :)


1 point by evanrmurphy 4186 days ago | link

To avoid polluting the global scope, you could keep your variables in a table instead:

  ; Our scope, which we'll use instead of the global scope

  (= dynamic-env* (table))
  ; Initial value 

  (= (dynamic-env* 'x) 5)
  ; Like your some-fn, just a function that uses x.
  ; Except that this references x in the table instead
  ; of the global scope 

  (def foo () (prn "x = " (dynamic-env* 'x)))
  ; Like let, but manipulates keys in our table
  ; instead of variables in the global scope 

  (mac dynamic-env*-let (var val . body)
    (w/uniq g-old-val
      `(let ,g-old-val (dynamic-env* ',var)
         (= (dynamic-env* ',var) ,val)
         (= (dynamic-env* ',var) ,g-old-val))))
  arc> (dynamic-env*-let x 10 (foo))
  x = 10
  arc> (dynamic-env* 'x)
I'm not sure if this addresses your threading issue though. This probably looks a lot like your code except that dynamic-env-let uses the table where your w/config uses the global scope.

And of course, if you were using this all the time you'd want to choose better names. Your fingers wouldn't be happy having to type "dynamic-env-let" very often. :P