Arc Forumnew | comments | leaders | submitlogin
With and withs
4 points by prestonbriggs 427 days ago | 8 comments
After reading old Scheme stuff, I wrote

  (def test ()
    (withs (val 0
            get (fn () val)
            set (fn (v) (= val v))
            dispatch (fn (m)
                       (if (is m 'get) get
                           (is m 'set) set
                           (prn 'eh?))))
which let me write things like

  (= a (test))
  (a!get) => 0
  (a!set 5)
  (a!get) => 5
and so forth. But if I rewrite the "withs" as "with", it all fails. Why's that?

3 points by i4cu 426 days ago | link

The reason why there's an 's' on 'withs' is that it's short for "with sequentially". Comparatively 'with' doesn't evaluate the bindings sequentially. So, for example, your 'val 0' is probably not being bound before the others are.


3 points by prestonbriggs 426 days ago | link

I wouldn't think it would make a difference. The other names are all bound to functions, so we should be able to bind them in any order.


3 points by akkartik 426 days ago | link

Try running without your code.

    arc> (help get)
    [fn]  (get i)
    Returns a function to pass 'i' to its input.
    Useful in higher-order functions, or to index into lists, strings, tables, etc.
      arc> (get.2 '(1 2 3 4))
      arc> (get!b (obj a 10 b 20))
      arc> (get.9 sqrt)
      arc> (map get.2
                '((a b c)
                  (1 2 3)
                  (p q r)))
      (c 3 r)

    arc> (help set)
    [mac] (set . args)
    Sets each place in 'args' to t.
These are the functions you end up calling because your dispatch can't see the earlier get and set bindings.


3 points by kostas 426 days ago | link

Look at the definition of with and withs at

The macro definition of with creates a function with all the names as inputs and the body of the with as the body of the function. The newly created function is called with the definitions of each name, which are effectively in independent namespaces.

The withs definition, however; recursively calls itself so that each succeeding name sees the definitions of previous names.

I believe the difference is historically due to higher speed of with. In modern programming it probably makes sense to use withs everywhere and only change to with in places where optimization is necessary.


4 points by akkartik 426 days ago | link

I actually tend to the opposite: use with everywhere unless I need withs. The reason isn't performance. It tends to make code more elegant to not rely on the order in which things are defined. And when I'm reading code, with gives me the warm fuzzies that the code is going to be cleaner. When I see withs I slow down to look at the dependencies between the bindings.


3 points by zck 426 days ago | link

Similarly to this, when I'm writing Java, I use `final`^1 everywhere I can. It's nice to be able to know that anywhere later where the variable declared final is in scope, it will have the same value as at the point it's set. I don't need to look through any code to see if it's rebound; I know it hasn't been.

[1] "final" is kind of like "const", if I understand `const` right. `final int x = 3;` means that it is an error to later have the line of code `x = 4;`.


3 points by prestonbriggs 426 days ago | link

OK, I get it, thanks. In scheme, I would use letrec for this situation; my intuition for Arc isn't very well developed.


1 point by prestonbriggs 426 days ago | link

I should have given more info. If, while using "with", I type

  (= a (test))
things look good. But if I then type

arc complains

  Error: " get: arity mismatch;\n the expected number of arguments does not match the given number\n  expected: 1\n  given: 0"
Adding to the general confusion, if I type

  (a!set 1)
arc complains

  Error: "Function call on inappropriate object #(tagged mac #<procedure: set>) (1)"