Arc Forumnew | comments | leaders | submitlogin
3 points by waterhouse 5018 days ago | link | parent

I do usually put definitions of dependencies first (fast-expt-* is in fact before mod-expt in my Arc file), but sometimes I shuffle my code around, and I'd be annoyed if it complained when I did that. I like having the freedom to do it, though I don't use it all that much. But mutually recursive functions are a good example too--it's impossible to have both functions come after their dependency.

> But you and rocketnia seem to place value on being able reference functions before they've been defined. So while I would be willing to trade that ability for implicit quotation, it seems you would prefer the reverse.

It is true that I'd prefer being able to permute my definitions over having implicit quotation, but that's by far not my only reason for disliking the idea. As I said, it's a fragile, shallow add-on feature that would confuse me (by giving me weird results for erroneous code) and that would make code harder for me to reason about (whenever I see a variable reference, either that refers to something that's been defined, OR it refers to a symbol! and I can establish the latter only by ensuring that it's not defined anywhere).

By the way, why do you think this feature is a good idea? I find two quotes that seem to suggest your reasoning:

1. "My sense is that something like this would rate highly in both complexity of implementation and convenience for programming." How do you get this sense? Do you write a lot of code that uses quoted symbols? Let's take a count in my big fat Arc file:

  $ grep -o "'" a | wc -l
     107
  $ egrep -o "[^' ()]" a | wc -l
   31362
  $ egrep -o "[a-zA-Z-+$*/]+" a | wc -l
    8261
Even discounting whitespace and parentheses, quotes account for about 0.3% of the characters I type. If we count symbols, about 1.25% of the symbols I use are quoted. Are you working on something that uses a bazillion quoted symbols--symbols which would have to be quoted individually (e.g. the list '(a b c d) just requires one quote)?

2. "I just think we're missing out on such valuable real estate here!" See the paragraphs in my grandparent post beginning with "Imagine if" and "In principle". Tacking things on just because you can isn't a good idea.



2 points by evanrmurphy 5018 days ago | link

> But mutually recursive functions are a good example too--it's impossible to have both functions come after their dependency.

You can do it by extending one of them:

  (def foo ())
  (def bar () (foo))
  (extend foo () t (bar))
I'm not saying this is a better way to define mutually recursive functions. Just pointing out that it's possible.

> add-on feature

Not sure what you mean by "add-on". Is xs.0 list access an add-on? This is whatever that is.

> why do you think this feature is a good idea?

It could unify the "." and "!" ssyntaxes to some degree by allowing table access with h.k instead of h!k in most cases. alists that you presently have to express with '((x 1) (y 2)) could be contracted to (x.1 y.2).

I haven't worked out all the useful applications of this yet but I'm finding it interesting and think there's some potential.

> fragile, shallow [...] Tacking things on just because you can isn't a good idea.

I'm generally disappointed by your flamey response to my interest in exploring a core language possibility that could make arc programs shorter. Your ideas and even complete disagreement are very welcome, but your overall tone is insulting. Perhaps I misread you.

-----

4 points by waterhouse 5018 days ago | link

> 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 5016 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.

-----

1 point by evanrmurphy 5018 days ago | link

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

Is there a general interest in moving ssyntax functionality to the reader? I've found some past discussions about it but wanted to know the present sentiment.

If ssyntax was processed at the reader-level, it would help in this particular scenario because then '(x.1 y.2) could evaluate to ((x 1) (y 2)) instead of (x.1 y.2).

-----

3 points by aw 5018 days ago | link

Is there a general interest in moving ssyntax functionality to the reader?

In the Arc runtime project, that was my assumption behind my choosing my matching library to implement the reader in Arc. The matching library is way more powerful than what would be needed to simply replace the Racket reader as-is; the goal is that when people want to experiment with different kinds of syntaxes or with extending ssyntax to work in more cases it will be easy to do.

-----

1 point by evanrmurphy 5018 days ago | link

That's good to know, thanks. :)

-----