As the next installment in our "A confession of stupidity" series [1], I never realized that before. :) Turns out that superimposing chars on top of each other to make other chars is an addictive game, though. Here are a few I came up with:
|S => $
:, => ;
++++ or //= => #
o/o => %
ao or aO => @
\S => &
-x or -X => *
|_ => L
/-\ => A
|3 => B
][ => I
|-| => H
C- => G
|= => F
|^^| => M or m
|< => K
|? or |> => P
|o => b
|) => D
-/_ => z
O, => Q
-| => +
|\| => N
bP => B
Unfortunately, few if any of these could be useful for Arc.
In your table, both the keys are symbols, which need the quote for reference. You can use dot ssyntax to retrieve vals for any keys that are numbers (since numbers don't need quote):
> Is the coder likely to make a mistake and reuse a Java method name as a fn argument name without realizing it. Probably not.
If this is more or less the deciding question, then I think your decision depends on whether Jarc follows Arc's design philosophy or Java's (or some other one). That is, if it's Arc's, then go with the lexically bound fns and let them make mistakes. If it's Java's or other, then since you say it's probably not a common mistake (and I agree) then you might still go with the coder's fns, but would have to consider the opposite.
Jarc is designed to follow the Arc philosophy. I'm trying to get away from the Java philosophy! ;-)
Good point about Arc letting users make mistakes. Jarc shouldn't go out of its way to avoid coding mistakes, but given two choices considering which might generate less coding mistakes seems a valid consideration.
But the driver is really that I want the compiler to generate the fastest code possible. Minimizing coding mistakes is a post-hoc rationalization.
Since the compiler doesn't (currently) do any type inference, I have to make a choice.
I was interested in the use of ? as a convention for predicates [http://arclanguage.org/item?id=2998]. Seems like Arc still doesn't have a consistent convention for that (and isn't ? still unclaimed territory?). On ! as a convention for setters, I use '= as an almost universal setter, making various specialized setters seem a bit unnecessary. For example, in most cases I'd probably do
(= foo.0 x) ; instead of (scar foo x)
Maybe '=car, '=cdr would be better than 'scar, 'scdr. The s-family just doesn't make much sense anymore since 'assign replaced 'set in its traditional role. Same thing for 'safeset. I'd change it to 'safeassign but it's so long. I thought about 'safe= but '= and 'assign aren't really equivalent (which may actually undermine my argument for '=car).
Yeah, if I rewrote arc from scratch I'd def use the ?/! convention more thoroughly. Your other suggestions seem more subjective, though :) I don't want to go overboard with consistency.
I'm thinking about forking arc, perhaps with an implementation in erlang/lfe (erc?) that would give us threading and pattern-matching and erlang's great scheduler for free.
One of the key core features I find myself wanting is generic functions so annotated types can easily overload primitives like prn and len. If I write an implementation of skip lists or doubly linked lists, for example, it's a royal pain to always remember to (do1 nil ..) at the repl because prn hangs in the presence of circular pointers or pointer explosion.
> Your other suggestions seem more subjective, though :)
I know, I'm afraid I'm earning a reputation here. ;) But out of curiosity, which ones were you thinking of? This point I feel strongly about, though I may have incomplete information:
> The s-family just doesn't make much sense anymore since 'assign replaced 'set in its traditional role.
My understanding is that at some point 'set became the new 'assert and 'assign the new 'set [http://arclanguage.org/item?id=9408]. The #\s in 'scar, 'scdr, 'sref and the "set" in 'safeset are presumably references to 'set, which no longer has anything to do with these functions (and macro). I know it's not a big deal, but isn't it an onion and potential source of confusion?
Yeah that was the one. scar/scdr don't have to make more sense than car/cdr. And they're kinda internal details, same as assign. Most of the time we'll just use (= (car ..) ..). That'll do, no?
I guess so, but changing 'set to 'assign would seem to indicate some sensitivity about the internal details on the language designer's part, and I think they are more important in code-as-spec languages like Arc. Granted you're right the naming of 'scar etc. isn't as important as the naming of commonly used forms like '=.
I believe set was renamed to assign to free up the name for a better use.
The way I think about it: code as spec implies the implementation should be concise and easy to read, and externally exposed names should be approximately hamming encoded. Internal names can be longer without compromising conciseness (which is measured in tokens) or readability.
It's not black and white, just relative priorities.
The escaping system is more robust than I realized. I think some of my concerns are definitely addressed with being able to assign escaped numerical characters, etc.
> However, I could see this being done: have nil be escapable, so that |nil| is the symbol you can rebind, while nil is the literal empty list. ...And then are they eq?
I looked into this and think it's kind of elegant now. 'nil is unescapable like non-special character symbols in general are [1]:
arc> (is 'nil '\n\i\l '|nil|) ; like your 'ach example
t
But () is escapable (as special characters typically are):
[1] I was frustrated momentarily when I couldn't escape 't until I realized it was the same way. As you pointed out, at least it is locally rebindable by default. And then I suppose 't isn't an especially desirable global variable name anyway.
Thanks for the excellent responses by yourself and waterhouse. I'll likely come back to this discussion several times in the near future (I want to try your patch), for now just a brief reply:
> More importantly, do you actually have a reason you want to rebind the canonical false value? I mean, basically all it could do is break. At least t is only boolean true because it's a symbol other than 'nil.
I don't have particular reason to redefine canonical false yet, but I did like the implications of all this on numbers for alists and would be very curious to hear reactions to that - maybe the idea is flawed or I need to explain it better [http://www.arclanguage.org/item?id=11714].
However, even if there were no immediate need to redefine 'nil, numeric symbols etc., I detect an ugliness with their redefinition being prohibited. I simply do not understand why ints would be untouchable when 'car, 'cdr, 'eval etc. - the true axioms of the language - can be reassigned in a heartbeat. If it has to be that only some of these symbols are sacred, I think it should be the axioms, not some literals. (Admittedly, there is some overlap, especially in 'nil territory.) Otherwise, it'd be cleaner to make everything rebindable or nothing so, and the former seems more in the spirit of Arc.
I detect an ugliness with their redefinition being prohibited.
But there's still a conceptual difference: numbers, strings, and characters are not variables to be redefined, but are syntax for constant values -- just like parentheses are syntax for "begin a list" and "end a list". It's like saying you should be allowed to change how the word "hello" is spelled.
Likewise, Arc works to make nil a literal value, (mostly) like a character or a string. Thus, redefining it is nonsensical. t isn't really a literal value, because any non-nil value is boolean true anyway. So, I agree that treating t as a variable could be allowed without breaking the current conceptual model.
I did like the implications of all this on numbers for alists and would be very curious to hear reactions to that
The reason 2 is the same as '2 isn't so much that quote special-cases numbers, it's that quote delays evaluation (which doesn't really happen for 2). On its own, foo evaluates to whatever it's bound to, so 'foo delays that. Compare with 2, which is "self-evaluating" -- as soon as we read it in, we know it's the number 2. Then '2 delays the evaluation of syntax that already had meaning before quote touched it. Hence, '2 is still just the number 2. Similarly for '#\a and '"a string".
You could make quote a special-casing operator, so '2 is different from 2 just because it's useful, but that doesn't let you redefine 2.
You could also change Arc so that there would be a layer between reading 2 and going "hey, that's the number 2". Then '2 would be more sensible and each 2 in your code could be a lookup to some value defaulting to...well, the number 2, I guess. But how do you distinguish 2-the-numeric-value and 2-the-variable if they're both spelled the exact same way? In the face of redefinition, (is (+ 1 1) 2) isn't an identity that would hold. What about extending this to less inductively-defined data types? How do you change #\a back to normal after (= #\a #\b)? Does it make (is "abc" "bbc") true? What if you first did (= "abc" "foo")?
The idea isn't just different, it creates a radically new language. That doesn't mean it's without merit. Off the top of my head, Common Lisp has reader macros that allow some syntax to be redefined, and PLOT (http://users.rcn.com/david-moon/PLOT/) lets you redefine syntax dynamically, though I'm not sure to what extent. But it's arguably one the first types of restrictions mentioned in http://www.paulgraham.com/ilc03.html (I don't mean to appeal to authority; it could just explain why Arc doesn't do this).
Another reason it makes sense to decouple numbers in particular from their symbols is that it indirectly solves the '! vs. 'alref problem we've had with association lists (another valient hack by aw [http://awwx.ws/alistcall]). Basically the problem has been, how do you cleanly implement !-alrefs for alists when there is the special case of al!n if n is a number? [http://arclanguage.org/item?id=78] While it's tempting to think this points to an issue with using '! for alists, in my mind the issue actually roots itself with numbers being inseparable from their symbolic representations. Only for numbers does 'n evaluate to n unconditionally, and as soon as you let them be independent, then everything falls into place with al.n returning the nth cadr of al as it always does for lists and al!n now able to do an alref on the symbol 'n.