Arc Forumnew | comments | leaders | submitlogin
2 points by rocketnia 4428 days ago | link | parent

I already understood the benefit of your quasisyntax operator. I agree that it makes desirable things easy to do by accident.

I don't agree that the original quasiquote should be difficult.

It's pretty much a matter of political spin. There's no need to work to make quasiquote difficult, but there's little need to work to make it easy either, since that effort would be better spent on quasisyntax. We can just neglect to give quasiquote any sugar, at the same time as we spoil quasisyntax with sugar of its own. We can also neglect to define quasiquote in the main language distribution altogether.

---

"I, personally, would probably call it something other than $quasisyntax"

If it's essentially a syntax that turns paren into a list literal syntax (with ,foo syntax as an escape), then maybe $lists or $es (evaluation structure) would be a nice brief name for it. :)



1 point by Pauan 4428 days ago | link

"I don't agree that the original quasiquote should be difficult. [...] We can just neglect to give quasiquote any sugar, at the same time as we spoil quasisyntax with sugar of its own. We can also neglect to define quasiquote in the main language distribution altogether."

tl;dr: I agree with you overall, so perhaps we're just using different terminology or wording, resulting in confusion.

Right, I'm not saying that users shouldn't be allowed to define $quasiquote if they want to, but given its problems and the fact that $quasisyntax is better overall, there's no need to provide $quasiquote by default in the language. And if there were a better alternative ($quasisyntax) in the language, then users would be encouraged to use it instead of defining $quasiquote themselves.

Even though Kernel goes out of its way to not provide $quote, it's trivial to add it in (literally just 1-2 lines of super-simple code). And it should only take ~20 lines or so to define $quasiquote, the same as it does in Arc. The only difference is Kernel doesn't have syntactic sugar for $quote, $quasiquote, or $quasisyntax.

I think syntactic sugar should have its own facility, such as reader macros (or something better), allowing users to add in syntax for $quote/$quasiquote/$quasisyntax/other things. But that's a different story.

-----

1 point by Pauan 4428 days ago | link

"perhaps we're just using different terminology or wording, resulting in confusion."

In particular, I disagree with this statement of yours: "I already understood the benefit of your quasisyntax operator. I agree that it makes desirable things easy to do by accident."

As far as I can tell, quasisyntax does not make it easy to do "desirable things" (like breaking hygiene) by accident. It does make it easy to do them on purpose.

I think our primary disagreement is that we're using different meanings for the word "accident". It seems to me that when I say "it should be hard to do dangerous things by accident" you take that to mean "I, the language designer, shall deem what shall be dangerous, and you, the user, shall not be allowed to do those things without jumping through crazy hoops!!"

---

But that's not what I'm saying. When I'm talking about "on accident", I'm referring to the user, not the language designer. Let me give an example. Let's suppose you had an operator in your language for deleting files.

To look at a real-world example, let's use the Unix command "rm". If you want to remove the file /foo/bar you would say this:

  rm /foo/bar
Okay, but let's suppose you mistype something (we all do it occasionally) so you instead accidentally enter this:

  rm / foo/bar
A difference of only a single character! But what the above command does is remove every file on your entire harddrive[1]. This is what I mean by "doing dangerous things by accident" and I'm sure some people have been burned by this[1].

Thankfully that's not what actually happens (at least on my computer): rm doesn't remove directories without specifying the -r option. So for removing files you say `rm foo` and for removing folders you say `rm -r foo`. Of course, that doesn't help if you accidentally type `rm -r / foo/bar`...

That's an example of making dangerous things difficult to do by accident, while still making it easy to do them on purpose when you want to.

---

So when I say that dangerous things should be difficult to do by accident, this is really just a different way of saying that "computers should do exactly what we want them to do, no more and no less".

Alternatively, it could also just be a rephrasing of the principle of least surprise, that computers should do what people expect them to do, rather than going off and doing crazy things that the user didn't want.

You don't want the computer to go berserk and do things you didn't intend for it to do. But in the (rare) case that you do want to, say, remove your entire harddrive, you should still be able to do so, and ideally it should be easy as well. Just not easy by accident.

---

My quasisyntax operator makes it super-easy to break hygiene when you want to, but it doesn't make it easy to do it by accident. You have to manually and explicitly add ,' to a symbol to make it unhygienic. Contrast that with quasiquote where it's easy to forget to unquote something, therefore quasiquote has the same power as quasisyntax, but makes it easy to break hygiene by accident.

Essentially the difference between quasiquote and quasisyntax is that quasiquote makes it easy to make mistakes, but quasisyntax does exactly what you would expect it to do, without making mistakes, while still making it really easy to break hygiene when you want to.

---

* [1]: I'm not actually sure about that... did older versions of rm automatically remove directories without specifying -r...? I vaguely remember some Unix horror stories, but they might have already been specifying -r in which case that won't help any.

-----

2 points by rocketnia 4428 days ago | link

I consider your quasiquote operator to make it easy to accidentally forget to quote things. Since we both consider that to be what people are most likely to want anyway, that's hardly a problem.

For a more detached example, consider someone who implements the same algorithm in Arc and Haskell. Their Haskell version uses call-by-need when their Arc version uses call-by-value, and at first they may even understand and disregard this discrepancy. Later they discover that one of these is detrimental--an undesirable accident. I consider the other one to be a desirable accident.

To me, this isn't just about whether the computer does what the user wants/expects it to do. It's about whether the computer does what the user doesn't know they want it to do. IMO, programming is all about specifying what one wants in really specific terms, even down to details one isn't truly sure about yet.

---

"It seems to me that when I say "it should be hard to do dangerous things by accident" you take that to mean "I, the language designer, shall deem what shall be dangerous, and you, the user, shall not be allowed to do those things without jumping through crazy hoops!!""

That's pretty much right. :) You have a good point that "by accident" is a key phrase, and your example of an accident is a nice thing to make difficult.

However, I still take any use of G3 in Kernel with a grain of salt, in case it turns out to be accidentally used in an "it should be hard to do things" way instead. There are many places where it's used for legitimate clarity of program behavior, but I'm not so convinced by these uses:

"Distinguishing long identifiers by case alone is error-prone, hence contrary to G3."

"One compromise is to G3 of §0.1.2. Naive traversal algorithms are dangerous; and, inevitably, the more readily available naive traversal algorithms become, the more readily the programmer can use them by accident."

"Most algorithms, however, are intended by the programmer to be im- mutable, and therefore, when an object is primarily meant to represent an algorithm, mutating it is a dangerous activity that ought to be difficult to do by accident (G3 of §0.1.2)."

I'm not convinced that these things are dangerous. I expect these kinds of accidents to cause run time errors nearly 100% of the time. They could do dangerous things in particularly contrived cases, but IMO, contrived cases are indistinguishable from non-accidents. (Yeah, I'm not being very empirical about this. >.> )

(When multiple antagonistic programmers are involved in a program, encapsulation prevents more than accidents, but I doubt that's the case under discussion....)

-----

1 point by Pauan 4428 days ago | link

"I consider your quasiquote operator to make it easy to accidentally forget to quote things."

Sure, but I'd argue that A) you want hygiene most of the time, so forgetting to $quote something happens less often, and B) in the case where you forget to $quote something with $quasisyntax, it usually throws an error. The reverse is not true: if you forget to $unquote something with $quasiquote, it's usually not an error, it fails silently until the bug is later discovered (possibly after a long time).

In other words, $quasisyntax not only chooses a default that you (the programmer) want more often (hygiene), but it also tends to throw errors earlier in case you (the programmer) mess up. That's why I consider $quasiquote to be bad. But in some hypothetical language where you want to break hygiene a majority of the time... then $quasiquote would probably be superior to $quasisyntax.

---

"To me, this isn't just about whether the computer does what the user wants/expects it to do. It's about whether the computer does what the user doesn't know they want it to do."

If so, then in order for the user to be guided into areas where they don't know they want it to behave in that way, then the language needs to encourage/discourage various behaviors in some way. Every language does this, in different ways, and to different degrees.

---

"but I'm not so convinced by these uses"

1) I agree, that doesn't seem to have much to do with G3 simply because if you accidentally use the wrong case for a long identifier, it's very likely to throw a runtime error that the variable can't be found.

2) I actually think this does justify G3 (though I agree it's pretty weak), for the same reasons I mentioned that using $quasiquote encourages you to use bad hygiene. If you don't provide a solid traversal algorithm, programmers are going to write their own awful algorithms which are no doubt broken.

I don't think Kernel goes out of its way to prevent you from writing stupid naive algorithms, and writing stupid naive algorithms is really easy. Instead, that's a rationale for not including naive algorithms in the core. You can still write your own naive algorithm, it just isn't going to be baked into the language, especially since the only gain of a naive algorithm is execution speed, not power or flexibility.

3) That particular part of the Report is talking specifically about operand capturing, e.g. fexprs. What it's saying is that when you apply a value (usually an acyclic list) to a fexpr, that fexpr could potentially mutate it.

This could cause some unexpected "action at a distance" so Kernel instead makes an immutable copy of the value and applies that to the fexpr instead. I'm not actually sure how I feel about that...

Incidentally, I believe that's how most (all?) Lisps do it: if you use (apply foo bar) in Arc, the foo function gets a copy of the list bar, not bar itself.

If you want the fexpr to be able to mutate its arguments... I would have suggested to pass the (mutable) list as a single argument to the fexpr, but... I'm not sure if that's actually possible... but it should be, right...? I would assume so.

---

"I'm not convinced that these things are dangerous."

I don't think they're any more dangerous than breaking hygiene. But Kernel already specifically mentions breaking hygiene as being dangerous, therefore calling those things dangerous is consistent with Kernel's viewpoint. So I suppose it depends on how dangerous something is before you personally (the programmer) call it "dangerous". But John Shutt apparently did consider them dangerous, hence their design in Kernel.

I personally wouldn't call them "dangerous". I think that word should be reserved for disastrous things like, say, deleting your entire hard-drive by accident. I would call things like breaking hygiene and whatnot "undesirable violations" (with the caveat that they can be desirable in certain circumstances, so they shouldn't be banned outright). If you have a better word to describe it, I'd like to hear it.

-----

2 points by rocketnia 4427 days ago | link

"In other words, $quasisyntax not only chooses a default that you (the programmer) want more often (hygiene)..."

...which is what I said :) ...

"...but it also tends to throw errors earlier in case you (the programmer) mess up."

I agree with this too. Throwing an error early is a nicer accident than throwing an error late.

---

"If so, then in order for the user to be guided into areas where they don't know they want it to behave in that way, then the language needs to encourage/discourage various behaviors in some way. Every language does this, in different ways, and to different degrees."

I don't see how this has a point any different from what I'm saying. :-p

---

"I don't think Kernel goes out of its way to prevent you from writing stupid naive algorithms, and writing stupid naive algorithms is really easy. Instead, that's a rationale for not including naive algorithms in the core. You can still write your own naive algorithm, it just isn't going to be baked into the language, especially since the only gain of a naive algorithm is execution speed, not power or flexibility."

In a customizable language (which Kernel isn't), to do something the most obvious way makes that part of the language more intuitive to customize, even if the most obvious thing is naive.

In a language with a culture of sharing black-box libraries (which Kernel would probably be, but for instance wart might not be), to do something the same way a library would do it makes for a more consistent experience.

Instead, for consistency's sake, Kernel advocates for library writers to write non-naive algorithms, ultimately making library-writing more of a chore.

This is totally a "worse is better" line of argument, so I don't expect to convert you with it so much as to convince you the ideals aren't so clear-cut.

---

"If you want the fexpr to be able to mutate its arguments... I would have suggested to pass the (mutable) list as a single argument to the fexpr, but... I'm not sure if that's actually possible... but it should be, right...? I would assume so."

I think Kernel calls the copy algorithm "copy-es-immutable," and IIRC, what it does is [treewise cons idfn _], but with an immutable cons. So if your mutable conses are hidden behind a variable name (to be evaluated) or a thunk, they'll survive. If you're just trying to eval (foo (my mutable list)), that won't work.

---

"I personally wouldn't call them "dangerous". I think that word should be reserved for disastrous things like, say, deleting your entire hard-drive by accident."

I agree. That's why I brought up those uses of G3; they just seem like examples of accidental errors being prevented, rather than accidental disasters being prevented.

---

"I would call things like breaking hygiene and whatnot "undesirable violations" (with the caveat that they can be desirable in certain circumstances, so they shouldn't be banned outright). If you have a better word to describe it, I'd like to hear it."

I don't know what you mean by "things like breaking hygiene and whatnot," unless you mean all the perhaps-not-so-dangerous things John Shutt considered dangerous when writing the R-1RK, and that isn't a very well-defined set of things. :-p I would probably call them "bugs."

Maybe G3 becomes something like this: While permitted on general principle, bugs should be hard to introduce by accident.

Hmm, I think this could be another, more upfront way to phrase the way G3 is actually used: The language should allow more expressiveness than is recommended for everyday use, but programmers on the fringe cases should have to jump through extra hoops.

I might actually support a G3 worded this way, but only because it suggests that it's easy to write full programs without jumping through any hoops, just by sticking to a subset of the language. Do you think there's a clear subset like that in Kernel? I'm not sure.

-----

1 point by Pauan 4427 days ago | link

"I don't see how this has a point any different from what I'm saying. :-p"

Right, I'm agreeing with you a lot, except that you seemed to be a bit against some of the things Kernel does, and I was pointing out that Kernel does that because it's trying to guide you toward a certain way of thinking that (hopefully) results in better programs. Whether you agree with Kernel's guidelines or not is another story.

---

"Instead, for consistency's sake, Kernel advocates for library writers to write non-naive algorithms, ultimately making library-writing more of a chore."

Library-writing already is a chore. If the only libraries available are hacky semi-broken things, then why would I use them? I can just write my own hacky semi-broken program faster than it would take to understand the library (usually).

So one of the primary benefits of libraries is that you can put a lot of extra effort into it, and then people use the top-notch shiny awesome library so they don't have to put all that effort into getting things perfect. Kernel just seems to embrace that and try to make even the core language itself rock-solid.

---

"This is totally a "worse is better" line of argument, so I don't expect to convert you with it so much as to convince you the ideals aren't so clear-cut."

I am generally an advocate of "worse is better", or else why would I be using Arc? When discussing Arc, I do tend to have a "worse is better" attitude about it. But at the same time, I also care about "doing the Right Thing", so my thinking shifts when talking about Kernel.

Essentially, Kernel seems to me to be a marvelous language that embraces the "do the Right Thing" attitude, whereas Arc seems to be a marvelous language that embraces the "worse is better" attitude. I like both of them, they have different atmospheres and feelings about them.

So, I think it really does depend on what you want to do, what you expect out of a language, etc.

I must say, though, Kernel has captivated me recently. I'm a total sucker for minimalism and elegance, while at the same time caring about speed and practicality. Inner conflict!

---

"unless you mean all the perhaps-not-so-dangerous things John Shutt considered dangerous when writing the R-1RK"

I was being hand-wavy and meaning things similar to hygiene breaking, like the 2nd and 3rd things on your list of things you mentioned in your post. So, not necessarily all the things John Shutt considered dangerous, but certainly some of them.

---

"Maybe G3 becomes something like this [...] I might actually support a G3 worded this way"

Indeed, though I already understood it to mean "accidentally introducing bugs into a program", though I'm not sure how John Shutt meant it... but judging by the way he uses it in Kernel, I'd say my interpretation is roughly correct.

-----