Arc Forumnew | comments | leaders | submitlogin
Scoping bug?
1 point by hasenj 5070 days ago | 6 comments
If you redefine a symbol inside a 'let block, what's the expected behavior?

Normally, (tag 'bb) produces:

  arc> (tag 'bb)
  <quote></quote>"</quote>"
But this behavior continues even when tag is bound to a different value inside a let block:

  arc> (let tag (obj bb 10) (prn tag))
  #hash((bb . 10))
  #hash((bb . 10))
  arc> (let tag (obj bb 10) (prn tag!bb))
  <quote></quote></quote>
  "</quote>"
  arc> (let tg (obj bb 10) (prn (tg 'bb)))
  10
  10


3 points by rocketnia 5070 days ago | link

That's because 'tag is a macro. When a form is compiled, its first element is checked to see if it's a symbol globally bound to a macro. The compiler has access to the list of local variables at this point (but not their values, since the code isn't running yet), and it could just leave a form alone if its first element is a symbol in that list, but it doesn't.

Should this be changed? Judging by the opinions expressed in http://arclanguage.org/item?id=11685, I'd say yes. But just like I said in that thread, all we need to do to get the behavior we want is to say do.tag!bb so that the 'tag symbol isn't the first element of the form. So for now you can get whichever behavior you want, but the more intuitive behavior takes a bit of "do." boilerplate.

PS: I'm a bit wrong in that thread, actually. It seems (= do.tab.key "something") actually does work just as well as (= .key.tab "something"), and I've been using the former in my code more recently for consistency's sake. I probably made that post based on experiences with an Arc implementation that's been fixed since then.

-----

1 point by hasenj 5070 days ago | link

Thanks for the link.

Looking at http://arclanguage.org/item?id=11697

It seems like Arc has no concept of scope.

It seems to me like when a symbol is bound to a name inside a function, that binding should temporarily override whatever is in the global symbol table; but that doesn't seem to be the case.

-----

1 point by evanrmurphy 5070 days ago | link

> It seems to me like when a symbol is bound to a name inside a function, that binding should temporarily override whatever is in the global symbol table; but that doesn't seem to be the case.

Macros are a special case. If it's a globally defined function, then the temporary binding overrides. But if it's a macro, then it doesn't.

-----

2 points by evanrmurphy 5070 days ago | link

I think it has to do with tag being a macro. Since arc doesn't have first-class macros [1], the compiler expands macro calls (i.e. instances where defined macro names occur in functional position) before run-time. In your example,

  arc> (let tag (obj bb 10) (prn tag!bb))
after the tag!bb ssyntax expands to (tag 'bb), tag is now in functional position, and it will be macroexpanded away before the semantics of let can come into play.

---

[1] http://arclanguage.org/item?id=11517

-----

1 point by hasenj 5070 days ago | link

Let itself is just a macro,

  arc> ((fn(tag) (prn tag!bb)) (obj bb 10))
  <quote></quote></quote>
  "</quote>"
Here were wrote a function which took an argument named 'tag, and yet the interpreter still thinks tag is a macro, when clearly it's not a macro in this scope.

If we were to wipe it first, then it would work as expected:

  arc> (wipe tag)
  nil
  arc> ((fn(tag) (prn tag!bb)) (obj bb 10))
  10
  10
If this is not a bug, then it's a design flaw. It means you have to be super careful when choosing names for function arguments, specially if you write a function taking a function or hashtable argument.

  (let name (some-function-generator)
    (name arg1 arg2 arg3))
What if name is defined as a macro by someone, somewhere?

You just defined it as a function, but the interpreter still thinks it's a macro. How can this not be a bug?

-----

2 points by evanrmurphy 5070 days ago | link

> Here were wrote a function which took an argument named 'tag, and yet the interpreter still thinks tag is a macro, when clearly it's not a macro in this scope.

Another way to think about it is that arc does have scope, but it doesn't apply to macros. Macros can only be defined globally (you can't write a local macro), and they're expanded before any of the normal scoping rules come into play.

> What if name is defined as a macro by someone, somewhere?

Yes: it is something you have to worry about and it is arguably kludgy. But again, it's only for macros. If you're overriding globally defined functions or variables of any other type, it works.

> You just defined it as a function, but the interpreter still thinks it's a macro. How can this not be a bug?

It's a thoroughly-discussed design choice that some people don't like. You already linked elsewhere in this thread to aw's proposal of how to change it if you want to give it a try. [1]

---

[1] http://arclanguage.org/item?id=11697

-----