"Interesting. If you make keyword args pervasive and optional like I do, you need a sense of ordering as well in the table, which weakens that imagery."
Oh I'd love to have pervasive keywords like Python (or wart), but it seems Racket doesn't support that. And I don't plan for Nu to become an interpreter. Keywords are optional in Nu, though (or will be, once I've implemented them).
---
"Making the symbols keywords didn't actually help me avoid that question at first glance."
I just like how there's a clean (and visible) separation between "lookup by key" and "lookup by index". It also avoids a runtime check as well, which is nice.
---
"Are you using the presence of keywords to disambiguate whether or not to insert the g1 (cdr g1) pairs in the withs?"
Yes. The code the compiler outputs depends on whether the argument is a keyword or not.
Pros: it's shorter to use because I don't need to repeat the keys.
Cons: it only works with syms. You can't eval an expr that returns a hash. It replaces the runtime check you're concerned about with that super ugly eval-inside-unquote. You can't import just a few of the keys so it feels a little like 'using namespace std' in C++ -- you may not know what vars you're going to get, and you may end up overriding bindings.
Perhaps I should just make it a new term. That would address the first limitation:
You're not going to be able to use (with hash ...) with a local variable 'hash unless you have at least one of these:
- Fexprs. An fexpr implementation of 'with can use the complete value of 'hash as it determines how to treat the unparsed body.
- Static typing with record types, so that a macro can use the type of 'hash as it determines how to treat the unparsed body.
- Some variant of JavaScript-style scope chain semantics, in the sense that a bare variable reference means (or can mean) a field lookup in general. IMO, this would be the most straightforward to add to an Arc-3.1-like compiler, since it's a matter of compiling foo to (scope 'foo), (with foo ...) to (let ((scope (shadow (scope 'foo) scope))) ...), and other scope-related things in their own analogous ways.
(def foo (a b)
(list a b))
(foo 1 2) -> (1 2)
(foo :b 2 :a 1) -> (1 2)
That doesn't work in Racket. You need to explicitly say that the arguments are keywords:
(def foo (:a :b)
(list a b))
In other words, arguments are either positional or keyword-based, but not both at the same time. This is different from Python, which lets you treat an argument as either one: