Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

>Callbacks are in no way "this generation's goto"

They are very much analogous to GOTO -- or even COMEFROM.

They have a similar effect to the control flow, and a similar adverse effect on the understanding of the program.

And Dijkstra's core argument against GOTO applies 100%:

"""My second remark is that our intellectual powers are rather geared to master static relations and that our powers to visualize processes evolving in time are relatively poorly developed. For that reason we should do (as wise programmers aware of our limitations) our utmost to shorten the conceptual gap between the static program and the dynamic process, to make the correspondence between the program (spread out in text space) and the process (spread out in time) as trivial as possible."""

>all alternatives to callbacks amount to incredibly fancy syntax sugar for hiding what is really happening behind the scenes anyway.

If, for, while, foreach --heck even map, reduce et co, etc are also syntax sugar for GOTO. Your point? Or adding the weasel word "fancy" somehow makes this particular syntax sugar bad?

Not to mention that there's nothing "incredibly fancy" about await, async, promises et co.

And if I wanted to know "what's really happening behind the scenes" I wouldn't programmer in Javascript in the first place.



You're not the first person I read mentioning "if" as a syntax sugar for "goto". It is not. In fact, "goto" needs "if" to replicate looping behavior.

Unless you imply "goto" can branch conditionally (e.g. je/jne/jg etc. from ASM) but that's not "goto". "Goto" means unconditional jump.


I thought of that Dijsktra quote too. It sheds light on what's wrong with the OP's proposal: in return for less nesting, it worsens the conceptual gap between the program (in text) and the process (in time). A poor trade.

I've found that nesting to indicate asynchronous control flow can be quite a good device for keeping the program text closely related to its dynamic execution. (It's true that such code is hard to read in JavaScript, but I don't think that's because of nesting per se.) It allows you to lay out synchronous logic along one dimension (vertically) and asynchronous along another (horizontally). I hypothesize that there's a quite good notation waiting to be brought out there; unfortunately, such experimentation tends to be done only by language designers in the domain of language design, when it really ought to be done in the context of working systems—and that's too hard to be worth the trouble unless you're programming in something like a Lisp.


>I thought of that Dijsktra quote too. It sheds light on what's wrong with the OP's proposal: in return for less nesting, it worsens the conceptual gap between the program (in text) and the process (in time). A poor trade.

That's like saying that "by using FOR instead of GOTO we worsen the conceptual gap between the program (in text) and the process (in time)".

Only we don't worsen it -- we just abstract it to a level in which we can reason about it better.

Higher level is not worse -- except if you consider "more distance from what is actually happening at the CPU" as worse. Which is not: historically the higher the distance, the more programmers got done.

We don't need to keep track of the actual low level process in time -- which with callbacks we're forced to. We just need to know how the steps of the process relate. Which await and co offer in a far better form than callbacks.


We're not talking about distance from the CPU. At least I'm not, and I'd be shocked if Dijkstra were. No, the issue is that a program has at least two different logical structures: its lexical organization in text, and its dynamic organization in time. You want these two to be as closely related as possible, because humans rely mostly on the program text to understand it.

"Time" here doesn't mean CPU time, it means logical time--the temporal (as distinct from textual) order of operations in the program. To put it another way, the "time" that matters for program clarity is not when stuff happens at lower levels (e.g. when does the OS evict my thread) but what happens when in the source code itself. This is not so far from your phrase, "how the steps in the process relate", so I don't see the disagreement.

I certainly don't agree, though, that the OP's design recommendations lead to higher-level or easier-to-reason-about code. Do you really think they do?


> ... the issue is that a program has at least two different logical structures: its lexical organization in text, and its dynamic organization in time.

That's a concise way to put it and I'll certainly remember and reuse it! Did you come up with it or did you come across it somewhere?


It's just a paraphrase of the Dijsktra quote. The same idea is implicit in the distinction between lexical and dynamic scope, which confused me for years before I got it... probably because "dynamic scope" is something of an oxymoron.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: