Arc Forumnew | comments | leaders | submitlogin
4 points by waterhouse 4804 days ago | link | parent

> I'm generally disappointed by your flamey response... your overall tone is insulting.

I'm sorry, my intent wasn't to insult you. (I'm glad you explained that, though.) I thought my words were clear. Let me explain:

I called the idea "fragile" because it would be easy to break code that depended on it--just by defining a new variable. You suggested a thing that would warn upon defining a previously-used-as-unquoted-symbol variable, but rocketnia and I brought up cases where the warning would be a false positive. I considered a more sophisticated warning system--one that had some kind of mechanical procedure for guessing whether an unbound variable was supposed to be an unquoted symbol or a function to be defined later--one that required the programmer to follow one naming scheme for unquoted symbols and another for functions to be defined later. My conclusion was that for this system to work, the programmer would basically have to tiptoe around it and be very careful, or else things would break. Hence, I thought the word "fragile" was appropriate, and used it.

I called it "shallow" because the maximum benefit, in the best possible case, is that you don't have to type the ' character most of the time. Contrast this with, say, learning to use lists when you're used to naming every single variable. Not only does it become easier to, say, compute the sum of the cubes of five numbers, but you can write a single function to compute the sum of the cubes of any number of numbers! And then you can make matrices--again, referencing them with a single variable--and writing a single function to deal with n x n matrices for all n! Without lists or other compound data structures, it'd seem really hard and annoying just to deal with 2 x 2 matrices, and 10 x 10 would seem impossible. There are deep and rich benefits to using compound data structures. But the only thing this unquoted symbols idea can possibly be good for is letting you omit the ' character; I therefore thought the word "shallow" was a good descriptor.

Regarding "Tacking things on just because you can isn't a good idea". Your motivation seemed like it might be, at least partially, something like this: "We can get strictly greater functionality out of Arc if we take some things that are errors and assign them a meaning in the language. Therefore, we should do it. Let's start looking for error cases we can replace with functionality!" Your comment "I just think we're missing out on such valuable real estate here!" added weight to this interpretation. And so I attacked it with a reductio ad absurdum, giving several examples of how one might "add functionality" in this way. I hoped to show that the line of reasoning "You get strictly greater functionality, therefore it can't be a bad idea" was wrong. I summed it up by saying "Tacking things on just because you can isn't a good idea."

> I'm not saying this is a better way to define mutually recursive functions. Just pointing out that it's possible.

And there are other ways to do it[0]. But it would be impossible to do it by just writing (def foo () (bar)) and (def bar () (foo)) and putting them in the right order. Hence, this idea would make such programs more complex/verbose. (Eh, perhaps you could set up a warning system and teach it to recognize mutual recursion. I think learning about this would distract the programmer somewhat, which isn't by itself a deal-breaker but is an undesirable aspect. I suspect there are more cases yet to be covered; and you'd still have to order your definitions properly--I don't think a compiler without psychic abilities could always tell what you were going to define later; and even if you were warned when you made a function with a conflicting name, it'd be annoying to have to give your function a new name, or to change the code that used that name.)

> alists that you presently have to express with '((x 1) (y 2)) could be contracted to (x.1 y.2).

Incidentally, I do find it annoying to type out a lot of such things, and I have a routine for dealing with that. Perhaps you'd find it sufficient? So whenever I want to make a big alist, I do something like this:

  (tuples 2 '(Jan 1 Feb 2 Mar 3 Apr 4 May 5 Jun 6
              Jul 7 Aug 8 Sep 9 Oct 10 Nov 11 Dec 12))
  ;instead of '((Jan 1) (Feb 2) ...)
Note that I've redefined "(tuples xs n)" as "(tuples n xs)". It is much better this way. :-} I could also use "pair", I suppose.

Oh, and, by the way, if ssyntax were implemented at the reader level--which I think it should be; I think the current situation is just a hack that will be changed eventually--you could write '((x 1) (y 2)) as '(x.1 y.2). [I see you address this in a sister post.]

And this example suggests that your intent goes beyond merely having unbound symbols evaluate to themselves. In my post I cite at the top of this thread, I addressed problems with trying to have ((x 1) (y 2)) evaluate as '((x 1) (y 2)).

> make arc programs shorter.

That is a worthy goal, one I'd forgotten about. It's good that you brought it up. I suppose the shortness of a program is kind of a good static measure, whereas objections like "It'd confuse me" are usually only temporary, and the programmer gets used to it.

But I do believe that a) using it would create either horrible risks of breaking things or annoying false-positive compiler warnings, b) therefore I'd never use it, so it wouldn't actually make my programs any shorter, and c) it would, inevitably, make debugging harder--instead of UNBOUND-VARIABLE errors I'd get diverse results, depending on precisely what happens when a symbol is put in the place of the unbound variable.

Now, (c) also applies to having xs.0 list/table/string reference work. But (a) and (b) don't. I do use it[1], and relying on it doesn't cause any problems like the fragility I've described. And the payoffs are pretty good. Many things are significantly shorter--e.g. m.i.j for reaching into a matrix, instead of (aref m i j) or, worse, (vector-ref (vector-ref m i) j).[2] The error-obfuscation objection still applies, but I think the benefits override the objection.

[0] I was thinking you could define them in the same lexical context:

  (with (foo-val nil bar-val nil)
    (= foo-val (fn () (bar-val))
       bar-val (fn () (foo-val))
       foo     foo-val
       bar     bar-val))
[1] In fact, arc3.1 doesn't even provide "hash-ref" or "string-ref" functions, so you kinda have to use (x n). "list-ref" at least could be implemented by the user in terms of car and cdr.

[2] I was going to add: "And since I don't need to specify the type of the data structure, sometimes I or my code can forget that detail. I could change matrices to be implemented as nested hash tables or vectors, and m.i.j would still be correct." However, this part could be done with a unified "ref" function that reached into all data structures.



2 points by evanrmurphy 4803 days ago | link

Thanks very much for clearing all of this up. :)

My reply has been delayed because I wanted to respond to a lot of your points in detail. I haven't found time to do that yet, but I thought I should at least say this before waiting any longer.

-----