News for hackers. Stuff that matters.
Re:You Can Throw() Anything in JavaScript – and Other Async/... by hambes on Friday April 08, 2022 @05:27AM (#30954988)
Please, please, please do not throw anything that is not derived from Error. Throwing literals or other things makes error handling so much less predictable, stable and useful. throw/catch is already bad, let's not make it worse than it needs to be.
Re:You Can Throw() Anything in JavaScript – and Other Async/... by mcherm on Friday April 08, 2022 @08:21AM (#30955996)
Can you provide some examples of specific situations in which throwing objects not derived from Error causes difficulty?

I ask for two reasons. First, because I find argument from authority to be a very annoying logical fallacy. I have actually heard people argue that in Python one should never use an exception to exit a loop, because "that's not how exceptions are supposed to be used". The people making this argument don't realize that every for loop in Python is always exited via an exception.

My second reason for asking is that I think your examples might all fall into certain categories. For instance, maybe there is a good argument for "never throw things not derived from Error in a way that they will escape your library, but within one library/module it's a perfectly fine technique". Looking at specific pros and cons would help uncover the cases where it is most and least harmful.

Re:You Can Throw() Anything in JavaScript – and Other Async/... by shadowgovt on Friday April 08, 2022 @08:54AM (#30956251)
If you're throwing weirdly shaped things inside code other people don't need to interface with, that's fine. Go nuts. You'll be creating a circumstance where any new person working with your code has to learn that you're doing something strange, but you won't really be impacting anybody else.

The fact that JavaScript allows non-Error-derived values to be thrown means that the first thing that any code that works with a thrown value has to do to be technically correct is runtime type inspection. You can't even assume the thrown value has a stack trace attached to it. So while technically the ship has already sailed, we add further complication to everyone's error handlers when we emit non-Error values via throw... Everyone's catch code has to grow support for handling whatever Byzantine type we've decided to toss out of our code today.

Re:You Can Throw() Anything in JavaScript – and Other Async/... by jitl on Friday April 08, 2022 @09:17AM (#30956440)
I like to have a stack trace. Please. Just in case you’re using throw for control flow inside an abstraction, if that ever leaks, anyone downstream is going to be in pain trying to figure out what is happening.

You can easily attach whatever interesting values you want to an Error instance, go nuts:

    throw Object.assign(new Error(“suspended”), { suspend: somePromise, retriesRemaining: 4, favoriteColor: 1 })
Re:You Can Throw() Anything in JavaScript – and Other Async/... by spicybright on Friday April 08, 2022 @08:48AM (#30956199)
> The people making this argument don't realize that every for loop in Python is always exited via an exception.

It's just all memory addresses under the hood, so why bother with variable names?

Only throwing exception objects is a layer of abstraction that makes error handling easier to handle.

Nearly all python libraries follow this pattern, and it's extremely easy to pass any variable you want to your custom exception for you to handle however you want.

Re:You Can Throw() Anything in JavaScript – and Other Async/... by exfascist on Friday April 08, 2022 @09:48AM (#30956723)
There's a very simple argument for hygiene and convention: The halting problem should make code unreadable, it doesn't largely because of hygiene and the shared knowledge formed by programmer culture. These things restrict the language to something that's just Turing complete and much easier to read.

There is a such thing as legitimately unreadable code, I've had to deal with it. Usually it's abusing things like the blurry line between objects and hashmaps in languages like js and Ruby.

Re:You Can Throw() Anything in JavaScript – and Other Async/... by mcherm on Friday April 08, 2022 @01:01PM (#30959669)
(1) I understand your point: consistently obeying sensible conventions makes code understandable and maintainable. That's a fairly good argument in favor of consistently using Error for all thrown things.

(2) One unrelated point: I suspect that the halting problem doesn't prove what you think it proves. The halting problem states that one can't build a tool to reliably analyze whether a given piece of code will end or will run forever. Some people seem to believe that this means some code will be "incomprehensible" -- that no code analysis can figure out what it does.

I am quite interested in the question of whether code can be made "incomprehensible" -- it has significance for things like securely protecting source code. But the halting problem would still be true even if "incomprehensible" code obfuscation is impossible and all programs can be "understood". Here's a good example of a program that might or might not halt:

  stop_at = input_number()
   x = 2
   while x < stop_at:
       if is_prime(x) and is_prime(x + 2):
           break
       x += 1
If the twin prime conjecture is true than that program always halts. If the twin prime conjecture is false than that program is an infinite loop whenever its input is larger than the largest twin prime.
Re:You Can Throw() Anything in JavaScript – and Other Async/... by sirsuki on Friday April 08, 2022 @07:22AM (#30955618)
If you need to use a rejection as a meaningful thing other than an actual exception then it really isn’t an exception is it? Instead fulfill the promise with an object that actually represents the state. Perhaps with a status property. Otherwise your code is going to look like a hot mess and you’ll just confuse generations of developers. Just because you can does not mean you should.
Re:You Can Throw() Anything in JavaScript – and Other Async/... by onion2k on Friday April 08, 2022 @06:50AM (#30955429)
Nonsense. You can treat Throw like a fancy "goto the nearest catch" if you want to. It works fine.
Re:You Can Throw() Anything in JavaScript – and Other Async/... by dspillett on Friday April 08, 2022 @07:20AM (#30955599)
That sounds fine as a quick hack in your own code that you never intend others to use, but if something like that escapes your library into calling code (isn't always properly trapped by your exception handling due to a bug) you are asking others to deal with a significant change to a commonly accepted standard behaviour.
Re:You Can Throw() Anything in JavaScript – and Other Async/... by the_other on Friday April 08, 2022 @07:42AM (#30955734)
Isn't "ensuring you always throw Errors" the same level of code cleanliness as "keep a top level catch in your code" or "document the errors and exceptions of your API"? If you make your team do one, you can make them do another.
Re:You Can Throw() Anything in JavaScript – and Other Async/... by chrisco255 on Friday April 08, 2022 @09:00AM (#30956294)
> you are asking others to deal with a significant change to a commonly accepted standard behaviour.

For a JavaScript developer, that's just Tuesday.

Re:You Can Throw() Anything in JavaScript – and Other Async/... by dspillett on Friday April 08, 2022 @09:58AM (#30956822)
And that Tuesday lasts all day until Friday. Sounds about right.
Re:You Can Throw() Anything in JavaScript – and Other Async/... by smt88 on Friday April 08, 2022 @06:56AM (#30955463)
If you're using throw for control flow, something is deeply wrong with your code.
Re:You Can Throw() Anything in JavaScript – and Other Async/... by regularfry on Friday April 08, 2022 @07:41AM (#30955730)
Now I'm wondering about throwing functions as continuations. This sounds incredibly messy. I love it.
Re:You Can Throw() Anything in JavaScript – and Other Async/... by shadowgovt on Friday April 08, 2022 @08:57AM (#30956274)
I... May have done something like this once in a scripting language interpreter to implement return and break.

Not in JavaScript. And using continuations passed down from above would have been the much more correct way to do things.

Re:You Can Throw() Anything in JavaScript – and Other Async/... by emteycz on Friday April 08, 2022 @08:27AM (#30956038)
Why not generators then?
Re:You Can Throw() Anything in JavaScript – and Other Async/... by regularfry on Friday April 08, 2022 @08:55AM (#30956263)
Because that wouldn't be perversely abusing a language feature for completely the wrong purpose.
Re:You Can Throw() Anything in JavaScript – and Other Async/... by the_other on Friday April 08, 2022 @07:39AM (#30955722)
`throw` is a control flow instruction. Simply using it at all controls flow within your code. Are you suggesting never to use it?
Re:You Can Throw() Anything in JavaScript – and Other Async/... by smt88 on Friday April 08, 2022 @11:54AM (#30958800)
I am suggesting to use it to throw exceptions. This narrow purpose is subtly hinted at by its name.
Re:You Can Throw() Anything in JavaScript – and Other Async/... by the_other on Saturday April 09, 2022 @11:15AM (#30968747)
I don’t see how it’s hinted in the name. “Throwing an exception” is a phrase from within computing that exists because the feature exists in some languages, not because it came into programming from English.

There’s also nothing about “exception” that means “error”. If anything, modelling exceptions as errors is the anti-pattern. If you modelled all exceptions as descriptors, you could save Errors for when something actually goes wrong.

Honestly though, I’m employing Socratic argument. I am only defending this position to learn about the opposite.

Re:You Can Throw() Anything in JavaScript – and Other Async/... by golergka on Friday April 08, 2022 @08:27AM (#30956031)
I think that the parent comment means "for control flow unrelated to error conditions".
Re:You Can Throw() Anything in JavaScript – and Other Async/... by onion2k on Friday April 08, 2022 @09:00AM (#30956292)
There isn't though. Exceptions are flow control. There's nothing particularly special about them internally in a JS engine. https://ripsawridge.github.io/articles/exceptions/
Re:You Can Throw() Anything in JavaScript – and Other Async/... by smt88 on Friday April 08, 2022 @10:15AM (#30957018)
I know. But what happens when someone inherits code that has a lot of this in it? They read a line, get to a throw, and then... how do they find all the catches that might apply?

Using that pattern is like a guarantee that your code will be spaghetti and meatballs.

This concept is so fundamental that it's even the topic of possibly the most famous CS article ever written[1], and I'd even argue that throw/catch is the worst-possible version of goto.

1. https://en.m.wikipedia.org/wiki/Considered_harmful

Re:You Can Throw() Anything in JavaScript – and Other Async/... by onion2k on Friday April 08, 2022 @11:44AM (#30958668)
When Dijkstra wrote his article [1], in 1968, I have no doubt he was correct. His point was essentially that code should reflect the flow of the application as closely as possible because it's immensely hard to keep everything in your head if it doesn't in the context of programming in 1968.

The thing is though, tools have moved on in the past 54 years. Seeing the flow of your code is a lot easier now. Debuggers are amazing things.

While I think his broad point (that code should be as simple and easy to follow as possible) still stands I don't really agree with it here. "goto considered harmful" could be used to argue that anything that changes and obfuscates the flow of a program when you compare the source to the compiled output is bad regardless of what it is, and that's plain silly. We'd have to throw away all manner of useful things like exceptions, macros, inheritance, etc.

I like Dijkstra's writing a lot, and he did groundbreaking work, but we have to remember to consider everything in the context of when it was written. This is a good example of that.

[1] http://www.u.arizona.edu/~rubinson/copyright_violations/Go_T...

Re:You Can Throw() Anything in JavaScript – and Other Async/... by smt88 on Friday April 08, 2022 @12:01PM (#30958896)
> in the context of programming in 1968

I was only pointing out that this is essentially the "original sin" of programming.

It's hardly an issue we've moved beyond, though. It's still one of the most widely-discussed anti-patterns[1] that I've seen in my career. There are dozens of essays and articles saying the same thing.

> Seeing the flow of your code is a lot easier now. Debuggers are amazing things.

There are no tools in any IDE or debugger that make it easier to look at a `throw` line and know all the places it might be caught. It guarantees the need for runtime debugging.

It's actually theoretically impossible to see all `catch` candidates for any particular `throw` in JavaScript because the dynamic nature of the language makes it possible for almost any function to call any other function at runtime.

This is still true in JavaScript of, say, a function call, but a function call can be more certain that its caller will be prepared to handle its output (especially when using TypeScript). When a `catch` is written without knowing all the possible things that can be thrown at it, it's very likely something will be thrown that isn't handled in the catch.

1. https://softwareengineering.stackexchange.com/questions/1892...

Re:You Can Throw() Anything in JavaScript – and Other Async/... by shadowgovt on Friday April 08, 2022 @08:55AM (#30956264)
Yes. In every way that goto is considered harmful it works fine.