Oh, it definitely throws strong typing right out of the window.
The reason I suggested it is because it would seem that almost all of the time where you go to do an increment on a nil value, you're working with an uninitialized element (not necessarily in a hash map) and treating that as 0 (as you're doing an increment) would in a certain sense be reasonable behaviour.
But I guess you're right, in the case where nil does represent an error, it'll be two steps backwards when you go to debug the thing.
Not really. Arc has macros and yet all the syntactic sugar ([], :, ~) is implemented in Scheme. Access to the read-table would be a start.
What I would really like to see though is a requirement for the code walker to be exposed and extendable.
Ah, ok! Now I get your point. Yes, it would be really useful to be able to extend syntax like that. However I believe readtable access should be limited. Let me explain.
I don't mean "limited" as in "dumbed down" but as in "predictable". It's nice to extend syntax, but it's even nicer when your editor can indent and colorize your program without a hitch. You are right: macros don't alter syntax significantly. And that's what makes them so nice: parens are still balanced, editors don't barf and, if you use with-gensyms and once-only, referential transparency is broken only where necessary.
A good place to start, IMHO, would be the ability to define operators: infix (like ':'), suffix ('~'), postfix and "wrapping" (like '[...]'). Operators would satisfy all of Arc's syntax-extension needs (unless I'm missing something). For example:
(operator wrapping #\[ #\] body
`(fn (_) ,@body))
(operator prefix #\~ symbol
`(fn args (not (apply ,symbol args))))
...or something like that.
Simonb: do you think this solution would fill the gap? Can you point out some situation where you would like even more control over the read-table?
The problem with giving only a limited support for something is that people will invariably want more and start to abuse the system. For instance with operators you risk ending up with a slew of little languages full of glyphs rich with semantic meaning (think Perl).
Macros allow you to build "up", to add new [abstraction] layers to your language but sometimes it would be nice to be able to go "down" as well and add new semantics that non-trivially interacts with the host language. Re-entrant continuations or proper tail recursion for CL come to mind. Another example of such friction is Qi [http://www.lambdassociates.org/aboutqi.htm] where all sorts of hacks (case sensitivity etc.) are needed instead of it simply being a library.
Theoretically one could design a language powerful enough that this would never be necessary but even then you would want code-walkers for optimisations. CL with it's compiler macros is a step in the right direction but it soon runs aground when you want to do things such CPS optimisations. Say you want to merge nested map-operations in CL:
(map 'vector #'^2 (map 'vector #'+ a b))
=>
(map (lambda (:g1 :g2) (^2 (+ :g1:g2))) a b)
This is something compiler macros are great for, but as soon as the inner map is wrapped in a function we have a problem. What our compiler macro sees is something like:
(map 'vector #^2 (vector+ a b))
and at that point we have no idea what vector+ looks like.
In terms of a compromise, access to the environment at compile-time would go a long way (CL has provisions for this, but the standard doesn't say anything about how the environment should look like) and maybe a facility to get function definitions (forced inlining if you will).
Indeed, it's not ambiguity, but visually a bit confusing. ("Visual ambiguity"? Certainly not in meaning.) But simonb, targeting the document at that audience doesn't have to come at the expense of the Scheme-experienced; after all, a trivial change "foo" to "bar" (#\f to #\b) would remove the confusion. As an aside, I doubt "readers with little programming experience" would be reading the tutorial for a pre-alpha language.
Even if we accept this premise, it applies only to the core language and (de facto) standard libraries (for which we can assume familiarity). As soon as the language is defined in therms of it's implementation it also serves as a coding guideline and this is where the problem lies.
You're right. I guess it's the same for the conditions system. It'd still be nice to have at least the condition handling operators built-in though, considering that they are used quite often.
Heh, not being able to bind to o by destructuring doesn't look like an intended behavior... Anyway, using `o' in order to mark optional arguments looked suspicious from the beginning. And now we know why.