News for hackers. Stuff that matters.
Re:You’re better off using Exceptions by ravenstine on Monday February 03, 2020 @11:33AM (#22225735)
My problem with exceptions isn't so much exceptions themselves but the way they're used.

The way I see it, exceptions should only be used for things that are irreconcilable, which most of the time is interpreter errors(e.g. undefined is not a function). In other words, I don't think it's that common that custom exceptions are needed outside of assertions to prevent the developer from doing something stupid. If you aren't using types, raising an exception can be helpful to provide feedback and useful information when data isn't formatted correctly.

Exceptions suck when they're used for problems that aren't actual problems. For example, if a query is made to an API for a record and that record isn't found, the SDK wrapping that API would raise a "Record not found" exception. What the hell? A record not being found is a normal thing! I've seen this kind of thing all over the place, and I recently had to write some application code to work around one of these useless exceptions. They literally tell you nothing and there's no way to solve them without catching/rescuing them. A null value, a plain "error" object, or an error argument in a callback would have been sufficient. If I need an exception to be raised for this kind of thing, I'll do it myself.

Re:You’re better off using Exceptions by Seenso on Monday February 03, 2020 @11:57AM (#22226056)
> A record not being found is a normal thing!

It's not a normal thing for code that needs that record that wasn't found.

> They literally tell you nothing and there's no way to solve them without catching/rescuing them. A null value, a plain "error" object, or an error argument in a callback would have been sufficient. If I need an exception to be raised for this kind of thing, I'll do it myself.

They tell you lots: you asked for something your code path wanted and your request couldn't be satisfied. Also, you've been helpfully kicked onto the alternative execution path to handle that situation.

Exceptions are a hell of a lot better than littering your code with null checks or error code checks, especially when you forget one and get a null pointer error or your code wanders away from the root cause and fails later.

Re:You’re better off using Exceptions by ravenstine on Monday February 03, 2020 @12:18PM (#22226293)
> It's not a normal thing for code that needs that record that wasn't found.

No offense, but I don't know where that idea comes from. Systems are checking for records all the time in ways where the absence of data doesn't necessitate throwing an exception.

For instance, a page, user, or piece of media on a website may have existed at one point but was since deleted, but still has a permalink floating around the net. Is it useful, in the case that someone clicks on such a link, to throw an exception when I can instead choose to render different page content when a record wasn't found? I'll never need a stack trace for that.

> They tell you lots: you asked for something your code path wanted and your request couldn't be satisfied. Also, you've been helpfully kicked onto the alternative execution path to handle that situation.

Why would I want a code path for expected behavior? I agree for cases like a failed connection, where the system is actually broken, but there isn't anything fundamentally broken about data absence.

> Also, you've been helpfully kicked onto the alternative execution path to handle that situation.

That's not only presumptuous, but if I wanted that to happen, I can do so myself.

> Exceptions are a hell of a lot better than littering your code with null checks or error code checks, especially when you forget one and get a null pointer error.

Hmmm...

  const record = store.findRecord(params.id);
  
  if (record) {
    render('show-record');
  } else {
    render('record-not-found');
  }

or...

  try {
    const record = store.findRecord(params.id);
    render('show-record');
  } catch(err) {
    if (err.name === 'RECORD_NOT_FOUND') {
      render('record-not-found');
    } else {
      throw err;
    }
  }
I'll let people decide which one is better. I personally prefer the first one.
Re:You’re better off using Exceptions by hombre_fatal on Monday February 03, 2020 @12:37PM (#22226582)
Well, in real code you are likely bubbling up an error in some way for your 404 Not Found and 500 Internal Error handlers to kick in.

    item = db.findItem(id)
    assert(NotFoundError, item != null)
    render('show-item', item)
upstream middleware:

    try {
      res = await downstream() 
    } catch(e) {
      if (e is NotFoundError)
        render('not-found')
      else
        render('internal-error')
    }
you can do this with other patterns for upstreaming errors like Result + Rust's handy short-circuiting, but your example doesn't demonstrate much. what about internal errors like your store throwing a database error, your first example doesn't even have a store capable of erroring? your comparison incomplete. and surely you don't do all error checking at every callsite no matter which pattern you use.
Re:You’re better off using Exceptions by clon on Monday February 03, 2020 @12:51PM (#22226767)
> Well, in real code you are likely bubbling up an error in some way for your 404 Not Found and 500 Internal Error handlers to kick in.

Which is essentially GOTO 404

A horrible idea that I see often in clever frameworks disobeying encapsulation and reasonable control flow in favour of magic

Re:You’re better off using Exceptions by _ZeD_ on Monday February 03, 2020 @01:15PM (#22227128)
That is a wonderful idea. You don't need to deal with 404, 500 or other stuff, you just write for the "happy path". The framework deals with the rest.
Re:You’re better off using Exceptions by mumblemumble on Monday February 03, 2020 @01:43PM (#22227441)
It's both wonderful and terrible.

On the one hand, it's terribly convenient when you're writing the code.

On the other hand, as clon says, it breaks encapsulation. Not necessarily, but I've rarely seen these style of Web frameworks used in a way that doesn't result in network communication concerns wormholing their way through the entire codebase. And it sometimes does do weird things with control flow. Again, not necessarily but in practice. For example, JAX-RS frameworks do the exception mapping off in some magic location that's outside the part of the call stack that you directly control, meaning that customizing the logic requires hacking some fairly complex special-purpose mechanisms into the framework.

I suspect that there's a way to achieve convenience without relying on spooky action at a distance. But one could be forgiven for looking at the way popular frameworks on popular platforms work and concluding that cleanliness must be the price of convenience.

Re:You’re better off using Exceptions by majewsky on Monday February 03, 2020 @01:29PM (#22227282)
Then you fill in a complex form with 6 object references, and the framework just spits out "NOT FOUND", which means "have fun figuring out which one is the missing object".
Re:You’re better off using Exceptions by joshuamorton on Monday February 03, 2020 @01:59PM (#22227616)
`raise MissingField(field_name)` solves this problem.
Re:You’re better off using Exceptions by ravenstine on Monday February 03, 2020 @02:01PM (#22227633)
At which point you end up doing the same work you would have had to do in the first place, except with extra lines for exception handling. ;)
Re:You’re better off using Exceptions by cjfd on Monday February 03, 2020 @01:01PM (#22226929)
The code example is not convincing at all. Obviously a single if is much cleaner than a single try/catch block but that is not the comparison. The if needs to be replicated N times for every N things that could fail and that are calling each other in a potentially deep call hierarchy. The try/catch block only needs to occur once at a level that is above all of the N things that might fail.
Re:You’re better off using Exceptions by ravenstine on Monday February 03, 2020 @03:50PM (#22228895)
That doesn't always make sense when you're dealing with a generic exception class. What you are assuming is that a try-catch block higher up in the hierarchy can handle a RecordNotFound exception for all its descendants, but that's not necessarily going to be the case. It's basically the inheritance problem in object-oriented programming, but in reverse. This is why I'm in favor if exceptions for non-broken states to not be a thing or at least be optional. Making a request to an API or database and getting a successful response returning no data(or a message that says data wasn't found) means that the code and the services in the system are actually working correctly, and throwing an exception is treating the situation like a code problem when it could(and often is) simply be a data problem, which is common and often expected.
Re:You’re better off using Exceptions by cjfd on Tuesday February 04, 2020 @10:51AM (#22236927)
Yes, the try/catch block is better if the catch block can handle exceptions for all its descendants. As always in programming YMMV and this is sometimes true and sometimes it is not and when it is not it is better not to throw an exception.

I agree that a database API should not itself throw an error if an empty result set is found. It may throw an error if there is an SQL error, though, and really should. When one gets an empty result set where this should not happen, for instance because a row was just inserted and one is in a transaction, the user code could throw an exception instead.

Making exceptions optional is something that I have indeed done in the past because some uses of the code could benefit from exceptions while other uses did not so much.

Re:You’re better off using Exceptions by dllthomas on Monday February 03, 2020 @01:21PM (#22227187)
In my experience, on the web there are two different kinds of things we might be fetching.

Some things are essential to the page we are rendering, and if they are missing we should 404.

Some things are ancillary, and if they are missing we should render a stub in their place. E.g., saying that a comment is from "deleted user".

Exceptions are a good fit for the former, where we want to unify every failure. They are a poor choice for the other case, where we want to treat each failure special.

Which case a given fetch represents is a choice that should be driven by the fetcher.

Re:You’re better off using Exceptions by AstralStorm on Tuesday February 04, 2020 @11:52AM (#22237813)
Why are they a poor choice for the latter?

They have a type, make it say MissingUserException and the special place can handle it in a special way. Ensure it is a subclass of some general exception type you also handle elsewhere and you're good.

Often people throw generic exceptions instead of using the type system.

Re:You’re better off using Exceptions by dllthomas on Tuesday February 04, 2020 @07:50PM (#22242934)
In the latter case you will often want to pass "data or the fact the data was missing" along to other functions. With a result value (of whatever form) that's trivial. With exceptions, it's certainly plenty doable but it's messy.
Re:You’re better off using Exceptions by cjfd on Monday February 03, 2020 @02:01PM (#22227642)
Sure, it depends on the situation. In the case you outline, there could also be room for an auxiliary function like fetch_alternatives({ preferred_resouce, second_best_resource , third_best_resource}) that would fetch them in until one can actually be obtained and throw an exception if all of them fail. Not that I am married to exceptions or anything. One should just use what is best in the situation that one is in. Actually, I think articles that claim that one language construct is better than some other language construct are quite silly. It mostly depends on the situation. Though, there also may be language constructs that are best left off deprecated, depending the language that you are using.
Re:You’re better off using Exceptions by irjustin on Monday February 03, 2020 @12:56PM (#22226852)
In general, I think this is why Rust uses `panic` since the name is way... angrier.

I like it. I wish that the concept of exceptions was closer to Panic because then we wouldn't be doing nearly as much flow control.

In the Rails world (where I live) looking top down, exceptions are handled via flow control or 500 pages. Anything that doesn't result in a 500 is effectively flow control.

While I agree with Rust's semantics, it generally isn't that bad to work around and knowing which is what.

Re:You’re better off using Exceptions by Seenso on Monday February 03, 2020 @12:52PM (#22226789)
> I'll let people decide which one is better. I personally prefer the first one.

That's JavaScript, right? That's probably not the best language to use to judge the concept of exceptions.

It's cleaner in languages like Java:

  try {
    Record record = store.findRecord(params.id);
    render(record);
  } catch(RecordNotFoundException e) {
      render('record-not-found');
  } catch (Exception e) {
      render('unexpected-error');
  }
Re:You’re better off using Exceptions by ravenstine on Monday February 03, 2020 @03:44PM (#22228822)
@Seenso You probably won't find, this, but I think I somewhat misunderstood the first thing you said.

My response to that would be that if it isn't a normal thing for your code to encounter a record not being found, then you should handle that state in whatever you see fit, whether that's by passing down a value or object reflecting that error state or throwing your own exception(yes, I do think such a thing can be appropriate). I still don't favor the latter, but at least with throwing your own exception your application can catch it at a higher level and will be less likely to mistake it for another exception of the same class that should be handled differently. If you are using an SDK that throws an error for a "record not found" type situation, it would certainly work in your favor if your application really does benefit from it, but I think a lot of code doesn't actually call for such a thing.

But my point is that there's no reason I can think of that an exception can't be totally optional in these circumstances. I don't think it should be assumed that everyone wants an exception. There's a reason why we use conditional syntax like if-statements because, if used try-catch syntax as control flow for everything, the flow would be bass ackwards and hard to understand. In my opinion, the example situation I described is on the borderlands where an exception might make sense but probably doesn't actually make things better.

Every project is different, and people might choose to use exceptions a lot, which is fine for them. I've personally been better off not relying on the exception-based control flow taught to me when I learned Ruby, but that doesn't mean I would come into a project and remove everyone's exception handling.

Re:You’re better off using Exceptions by kstenerud on Monday February 03, 2020 @03:14PM (#22228477)
Your first example loses the real reason for the error and just assumes "record-not-found", so it will give misleading errors when the network drops for a moment, possibly resulting in an attempt to insert a duplicate record if the code tries to add-if-not-found. That'll make for some debugging fun!

And this is the problem with error checks: They're purely optional as far as the language is concerned, so we keep getting them wrong or forgetting things, even when we're being careful.

Re:You’re better off using Exceptions by necovek on Monday February 03, 2020 @02:46PM (#22228161)
That's a pretty good example. Now imagine you want to structure your code in a way that render('record-not-found') happens in a caller to that block. So exceptions as a general approach work pretty well to allow simple code organisation according to your needs.

And you are the one who knows best if something is an expected failure, so wrap that up in a fetch_one_or_none() — as a matter of fact, most DB interfaces I work with have an API of the kind.

Basically, exceptions are a decent way to keep what might need to be a separate control flow, well, separate. And you can choose at any time to "join them in". As a concept, they are quite like interrupts on the very low (hardware) level, so you can learn only one "tool" to deal with them.

(And yes, I can trivially find cases where I want errors to bubble up when a record is not found, eg. a required configuration record or similar)

Re:You’re better off using Exceptions by sombremesa on Monday February 03, 2020 @12:29PM (#22226471)
Many years of experience tell me that you're going down the futile path of getting a tiger to change its stripes. As more and more devs get minted, prepare for codebases (and libraries) to get a LOT more gnarly. Even so, it's a good thing to lower barriers of entry and we can be discerning about where we get our code.
Re:You’re better off using Exceptions by je42 on Monday February 03, 2020 @02:27PM (#22227950)
The article is fairly specific:

The first example: - no stack trace - loosing the specifics of error to troubleshoot.

The second example: - explicitly discards the stack trace - explicitly discards the error specifics.

Hence, if this is really what you want. fine, but in a lot of cases you do want to see stack traces and the exact reasons (and meta data why an error was thrown).

Re:You’re better off using Exceptions by iainmerrick on Monday February 03, 2020 @12:34PM (#22226534)
>> A record not being found is a normal thing!

> It's not a normal thing for code that needs that record that wasn't found.

This is something of a religious dispute and there are arguments both ways.

But I think it’s important to note that an exception is vastly more expensive than a simple function call or return value. So I’d say you need a really good reason to use exceptions.

I agree with the GP that in general, “lookup failed” is not an exceptional error. If it always succeeds, why are you looking up something in the first place?

I agree with the original poster that exceptions do have their place, even though they’re expensive.

If you have the primary key of a database object that you know to be correct, and you try to retrieve that record but fail, that might legitimately be an exception (unless having records deleted from under you is a common occurrence in your app).

Re:You’re better off using Exceptions by dnautics on Monday February 03, 2020 @01:38PM (#22227370)
I don't see what the problem is. The API should expose two methods: `fetch()` which returns, say, nil if there's no result (or an error monad or error tuple, depending on your language), and say `fetch!()` (or `fetch_throws()` if your language doesn't support exclamation points) which raises an exception if there isn't a result. The programmer gets to choose, on a case-by-case basis.
Re:You’re better off using Exceptions by iainmerrick on Monday February 03, 2020 @03:02PM (#22228344)
Agreed, it’s ideal to have both options available.

Kotlin gets this right for the most part (although I think it would be better if it had checked exceptions).

Re:You’re better off using Exceptions by kenoyer130 on Monday February 03, 2020 @12:36PM (#22226560)
In Java/C# land exceptions are EXPENSIVE. Like magnatudes more expensive. You have to build a full stack trace etc. Removing places in the code where it is "Throwing exceptions for non exceptional circumstances" has a dramatic performance increase benefit.
Re:You’re better off using Exceptions by aratauto on Monday February 03, 2020 @01:10PM (#22227063)
Technically in Java it is possible to create an exception object once, and throw it multiple times, making throws much cheaper as the stack trace is filled during the object's construction only.
Re:You’re better off using Exceptions by acidictadpole on Monday February 03, 2020 @04:10PM (#22229141)
Does this actually save much time? I thought it was the throw mechanic that was slow, rather than just creating the exception?
Re:You’re better off using Exceptions by aratauto on Monday February 03, 2020 @06:43PM (#22230655)
According my unscientific tests, it is about over 100 times faster. On my laptop I can throw one million exceptions in 15ms millisecond, when reusing the same exception objects, compared to 2 seconds when creating a new exception object every time with a quite shallow stack.

When a new exception object is created, the slowest operation is filling information about the stack trace. It is possible to override Exception's fillInStackTrace() with an empty implementation. In this case throwing exceptions with new exception objects, is only slightly slower than using one exception object (17ms vs 15ms for 1M throws).

Deeper stacks make difference even bigger. Adding 100 nested invocations to the stack slow downs the classic approach (a new exception object created just before invocation) to 9 seconds, while alternative approaches are not affected.

Re:You’re better off using Exceptions by haagen on Tuesday February 04, 2020 @10:29AM (#22236616)
Re:You’re better off using Exceptions by ReidZB on Monday February 03, 2020 @01:11PM (#22227080)
The HotSpot JVM may decide to stop building stack traces in some circumstances to improve performance (see the 'OmitStackTraceInFastThrow' option, enabled by default). Not sure about other languages / runtimes though.

That said, I agree exceptions should be reserved for exceptional circumstances. Something like checking if a record exists or not should probably use something like Optional instead, unless you are in a situation where a record "should" exist but doesn't (which is itself an exceptional case).

Re:You’re better off using Exceptions by iainmerrick on Monday February 03, 2020 @12:41PM (#22226642)
C++ too. I suspect it’s true in almost every language.

Maybe not Python? But Python is slow regardless.

Re:You’re better off using Exceptions by petters on Monday February 03, 2020 @12:55PM (#22226839)
In C++, exceptions are often faster than manual error checking when errors are rare.

But C++ does not provide a stack trace.

Re:You’re better off using Exceptions by safety-second on Monday February 03, 2020 @02:37PM (#22228074)
C++ exceptions are only good if you use them like signals from C or panics in Go. This means you have to use error values for 99% of errors or you lose this benefit. The fact that the STL sprinkles exceptions everywhere doesn't help this. C++ exceptions are so non-deterministic and slow that every real-time system disables them just to be sure.
Re:You’re better off using Exceptions by renox on Monday February 03, 2020 @05:14PM (#22229880)
> But C++ does not provide a stack trace

Which makes exception in C++ a very, very bad idea!

My reaction to 'the test fails because map::at threw an exception': stupid STL!!

A core dump would be so much easier to analyze.. Gdb's 'catch thow' is wonderful (well, it is after I fixed the part of our codebase which use exceptions as a control flow mechanism)

Re:You’re better off using Exceptions by nemetroid on Monday February 03, 2020 @06:13PM (#22230428)
> My reaction to 'the test fails because map::at threw an exception': stupid STL!!

> A core dump would be so much easier to analyze..

Uncaught exceptions call terminate(), which by default calls abort(), which generates a core dump. So if you want a core dump, just avoid catching the exception.

Re:You’re better off using Exceptions by renox on Tuesday February 04, 2020 @04:57AM (#22233946)
Except that I didn't put all these "catch".. But you're right, that's what should be done (or at least, rethrowing the exception from the catch block).
Re:You’re better off using Exceptions by AstralStorm on Tuesday February 04, 2020 @11:57AM (#22237897)
C++ can have a stack trace, there are enough libraries providing this functionality and even compiler extensions. Say, libunwind, though you will have to demangle names. And a debugger will see the stack as it is.

Also works in C.

Re:You’re better off using Exceptions by iainmerrick on Monday February 03, 2020 @02:48PM (#22228191)
You don’t always get a stack trace, but it still has to unwind the stack, calling destructors as needed, and check the exception’s type against each catch block.
Re:You’re better off using Exceptions by earenndil on Monday February 03, 2020 @02:53PM (#22228232)
Hence 'when errors are rare'.
Re:You’re better off using Exceptions by iainmerrick on Monday February 03, 2020 @02:59PM (#22228303)
I guess we’re violently agreeing? Exceptions are an order of magnitude (or several orders) slower than function calls and returns; but that can still be efficient overall, if only a tiny fraction of calls fail.

I’d simply add that most people greatly underestimate how expensive exceptions are, even in C++.

Re:You’re better off using Exceptions by AstralStorm on Tuesday February 04, 2020 @12:00PM (#22237930)
Calling the destructors is identical to ending any scope in C++, including function calls. Where is that extra expense?
Re:You’re better off using Exceptions by iainmerrick on Tuesday February 04, 2020 @12:33PM (#22238370)
You likely have to parse exception blocks and maybe chase pointers to find the objects to destroy. In the happy path, you can just call the destructors directly.
Re:You’re better off using Exceptions by baddox on Monday February 03, 2020 @12:38PM (#22226585)
> It's not a normal thing for code that needs that record that wasn't found.

In many popular programming languages, the way to check whether some value has a certain property is with an “if” statement. It would be very odd to replace every code path inside an “if” statement with exception control flow simply because that code path “needs” some condition to be met for it it to execute.

Re:You’re better off using Exceptions by erik_seaberg on Monday February 03, 2020 @04:19PM (#22229237)
If a user doesn't exist, any code that relies on having a user is broken, and I want a guarantee that code can't be reached. Throwing does that, mapping an Option does that, but "if" doesn't.
Re:You’re better off using Exceptions by baddox on Monday February 03, 2020 @06:39PM (#22230620)
That's just a matter of a specific language's syntax, type-checking, or linting. Pattern-matching in OCaml [0] will in most cases warn about non-exhaustive checks. It seems like TypeScript has something similar, although I haven't used it [1].

[0] https://www2.lib.uchicago.edu/keith/ocaml-class/pattern-matc...

[1] https://dev.to/babak/exhaustive-type-checking-with-typescrip...

Re:You’re better off using Exceptions by hinkley on Monday February 03, 2020 @02:09PM (#22227745)
I was watching this the other day:

https://www.youtube.com/watch?v=AnZ0uTOerUI Unconditional Code by Michael Feathers

One solution to this problem is discussed toward the middle: giving data instead of asking for data avoids error conditions. Doing so pushes use of the data farther down the call tree and pulls acquisition up near the top, where we are closer to the user and thus able to more clearly decide what if anything to do about these corner cases.

Re:You’re better off using Exceptions by UK-Al05 on Monday February 03, 2020 @12:26PM (#22226404)
> Exceptions are a hell of a lot better than littering your code with null checks or error code checks, especially when you forget one and get a null pointer error or your code wanders away from the root cause and fails later.

That's basically limitation of the language. Null checks and result checking can basically be abstracted away with non-nullable types, option types, and result types and bind.

You only need to do match or check right at the edge, so they're not everywhere.

Re:You’re better off using Exceptions by joshuamorton on Monday February 03, 2020 @02:03PM (#22227666)
Result types are exceptions with different performance characteristics.

Like, handling a checked exception (Java) and a Google-cpp StatusOr<T> or a rust Result<T> provide extraordinary similar code. Unchecked exceptions provide a bit of extra dynamism, and languages without either are anti-user.

Re:You’re better off using Exceptions by UK-Al05 on Monday February 03, 2020 @02:32PM (#22228013)
I find result and option types compose nicer using monadic style composition.
Re:You’re better off using Exceptions by cheez on Monday February 03, 2020 @01:54PM (#22227549)
SQLAlchemy does this well:

obj = session.query(MyObject).one_or_none() # no exception if missing

obj = session.query(MyObject).one() # exception if missing

Re:You’re better off using Exceptions by yawboakye on Monday February 03, 2020 @02:19PM (#22227869)
> It's not a normal thing for code that needs that record that wasn't found.

Why call it then?

Re:You’re better off using Exceptions by shadowgovt on Monday February 03, 2020 @11:41AM (#22225843)
I find the mindset that exceptions are the right way to handle ordinary scenarios symptomatic of what I call "happy path coding:" assuming that the stars are always perfectly aligned for your program to work, and nothing ever goes wrong, and if it does it's someone else's problem.

It's a fine approach for prototyping but we should be highly suspicious of it for code people rely upon to work. As complexity approaches infinity, the odds of the system being "happy path"-aligned approach zero.

Network-relevant programming (such as web UIs), in particular, really highlights this fact (since any given network request is always allowed to fail, and "user closes their laptop or mobile device, moves somewhere else, and resumes work on an entirely different physical network" has gone from a rare occurrence to an extremely common one in the past two decades).

Re:You’re better off using Exceptions by AstralStorm on Tuesday February 04, 2020 @12:01PM (#22237955)
On the other hand, do you really want to bubble error results through layers of network stack and parsers, when handling is almost always the same?
Re:You’re better off using Exceptions by seanmcdirmid on Monday February 03, 2020 @11:51AM (#22225971)
If you expected the record to be found, the failure of finding it is an exception. If it was an open question, then it isn’t.

This is why API generally have checks that allow developers to avoid that failure if the failure is expected (eg Record.exists). What you are suggesting is simply a reverse order (check after vs check before). I think check before leads to a much cleaner API than one that dumps a null or failure code instead.

Re:You’re better off using Exceptions by pjc50 on Monday February 03, 2020 @12:10PM (#22226207)
"Check before" is a race condition nightmare - for anything where you care about concurrency, you must do the thing and then see whether it succeeded or not, assuming that the underlying layer is basically sound in this regard.

The world is full of bugs of the form "does this file exist? no? OK, open it for writing", which is exploitable by dropping a symlink in there between the check and the open.

The classic primitive CMPXCHG works like this too; you use it as you would a "store", but one that might fail if another thread has changed a value in the meantime.

Re:You’re better off using Exceptions by seanmcdirmid on Monday February 03, 2020 @12:22PM (#22226353)
That case is even much more exceptional: where the record existed when you checked but didn't in the millisecond afterwards when you actually opened it. But if that is common, then I would guess a concurrent check for existence and open if it is might be necessary.
Re:You’re better off using Exceptions by iainmerrick on Monday February 03, 2020 @12:38PM (#22226583)
That’s a very, very common source of subtle bugs (often exploitable as security bugs) that are hard to spot and hard to test for.

It’s good practice to design APIs to make race conditions less likely, by explicitly not splitting operations across multiple calls.

Separating “exists” and “get” into separate calls is a disaster.

Re:You’re better off using Exceptions by seanmcdirmid on Monday February 03, 2020 @12:56PM (#22226864)
I would compare this to a map API: an access could throw if a key wasn't present, but you can check to see if the key was in there first anyways. As long as the map isn't being used concurrently, it isn't that much of a problem, and if it is being used concurrently, then you need a different design. In the former case, separating "exists" and "get" would be considered over-engineering.

I guess databases and file systems are different because concurrent access is the norm, not the exception, and APIs should be designed accordingly. But for most of your in-memory structures, you probably don't want them dealing with concurrency because they aren't going to be able do that very well anyways (instead, deal with concurrency outside of the data structure and have them throw when inconsistencies from bad concurrency policies arise).

Re:You’re better off using Exceptions by XMPPwocky on Monday February 03, 2020 @01:44PM (#22227447)
For most implementations of maps (hashtables and various tree-ish things), even in the single-threaded case, doing .exists and then .get is about twice as expensive as doing a .get that returns an Option (or nullable reference, default value, whatever)- you have to do the map lookup twice.

(Okay, probably not twice as slow, since the cache will be hot, but still.)

Re:You’re better off using Exceptions by seanmcdirmid on Monday February 03, 2020 @02:43PM (#22228124)
Not twice as slow. But you are forgetting the case where you know the element is already in the map, and you want to call map.get() without wrapping it in an option.
Re:You’re better off using Exceptions by pjc50 on Monday February 03, 2020 @04:35PM (#22229425)
C# does this fairly nicely with an "out" parameter: https://docs.microsoft.com/en-us/dotnet/api/system.collectio...

Or if you "know" it's there call the version that throws an exception if it isn't.

Re:You’re better off using Exceptions by seanmcdirmid on Monday February 03, 2020 @08:23PM (#22231374)
I haven't used that aspect of the Dictionary API at all in the 9 years programming C#, it is just too unwieldy to have to define a separate local variable to hold the result of the get. It also doesn't scope the out assignment (if the get fails, you can still read the out variable bound). I'm rarely in the case where I don't expect something to be in a map anyways, and when I do, I have an extension method with a default value returned if the key doesn't exist (or in some cases populate). Keeping expressions clean is important.
Re:You’re better off using Exceptions by weberc2 on Monday February 03, 2020 @09:10PM (#22231677)
Exceptional doesn’t mean uncommon, it means your program is in an invalid state. Your programming style is inherently unsafe, and you are derelict of your most basic responsibility as a software professional if you apply it on any software of consequence. This is why we can’t have nice things.
Re:You’re better off using Exceptions by ravenstine on Monday February 03, 2020 @12:02PM (#22226108)
I don't agree. There is nothing inherently irreconcilable about a record not existing. Anyone who expects a database to always have records and that the absence of a record is an "exception" has a very strange way of thinking. It's like if a car was programmed not to start and to turn on an obnoxious alarm bell because the windshield wiper fluid is empty, and the technicians built in a jumper wire to short that circuit and allow the car to run.

Then again, maybe there are cars built that way. Oy vey.

I would never expect that a call to `Record.find(...)` would always find records, and that the failure to find a record means that something is broken. The absence of data is usually all you need to handle control flow, and treating absence as a failure is presumptuous of API engineers. Having to account for a specific exception just adds more lines of code that could be easily avoided.

A better use of an exception would be for a system failure like this: "Connection Failed"

Re:You’re better off using Exceptions by Seenso on Monday February 03, 2020 @12:23PM (#22226362)
> There is nothing inherently irreconcilable about a record not existing.

IMHO, that's being a bit too ideological. It's better to think about it in terms of how you'd want to respond to the condition, and pick your tool appropriately.

For instance, if I'm asking for a record by ID, then a record not found exception is a good fit. I was probably going to do something with the record, but now I can't, and the exception idiom tool the condition to be dealt with where it happened even if I forget.

If I'm asking for a set of records matching a criteria, and nothing matches, then a record not found exception is a poor fit. Code that can deal with a populated list usually can deal with an empty list just fine, and using an exception just adds friction.

If I'm asking for a set of records matching a criteria, and the database is is down, then an empty list is a poor fit. I have information about the connection error I need to communicate, so it's better to use an exception.

Re:You’re better off using Exceptions by Rusky on Monday February 03, 2020 @12:31PM (#22226499)
> Anyone who expects a database to always have records and that the absence of a record is an "exception" has a very strange way of thinking.

This isn't something you can make universal statements about, because it depends on context.

If the program knows it just put or saw the record there, is it strange to assume it's still there? If the program completely controls the database and something else in it implies the record is there, is it still strange to assume?

Sometimes broken assumptions can only signify that something has gone very wrong, and it's not worth handling them at a fine-grained level. That leads to the "gotta catch em all" antipattern the article mentions.

Re:You’re better off using Exceptions by ryanianian on Monday February 03, 2020 @12:24PM (#22226376)
If you're wrapping every call in `try/catch` or equivalent, then something's probably wrong in your invariants. If customer.phoneNumber is a non-null foreign-key, your application should safely be able to assume that Phone.findByNumber(customer.phoneNumber) will succeed. If you don't get to assume that, then you have business-logic errors elsewhere and your best bet is to crash.
Re:You’re better off using Exceptions by barrkel on Monday February 03, 2020 @12:10PM (#22226206)
Of course, if you're in a web app, and you've received an email address, and you can't find a User record for that email address, a perfectly valid approach would be for the fetch to throw a 'not found' exception and to generically handle all 'not found' exceptions in request handlers to return 404 status codes.
Re:You’re better off using Exceptions by appleiigs on Monday February 03, 2020 @12:19PM (#22226313)
Then would you be nesting a number of exceptions. Some maybe real 404 exceptions, but some would be zero records found. And I think the zero records found should be handled in the business logic (if statements, switch/case), not in the exceptions.
Re:You’re better off using Exceptions by barrkel on Monday February 03, 2020 @05:25PM (#22229981)
The expectation of a single result should be encoded in the API, not the business logic. It's a very common expectation for e.g. identifiers found on http paths.
Re:You’re better off using Exceptions by joshuamorton on Monday February 03, 2020 @02:06PM (#22227699)
If I expect exactly one result, zero results is exceptional. If I expect zero or more results, zero results should be handled by the business logic.
Re:You’re better off using Exceptions by horsawlarway on Monday February 03, 2020 @03:54PM (#22228952)
>There is nothing inherently irreconcilable about a record not existing

This just isn't true. It depends on what the record is, and what state you're in (aka: CONTEXT).

incredibly clear example: 1. User logs in 2. User record no longer exists 3. Exception

That's not a recoverable situation, and the client should see that as an unexpected error.

Re:You’re better off using Exceptions by ketzu on Monday February 03, 2020 @06:04PM (#22230370)
> There is nothing inherently irreconcilable about a record not existing

> This just isn't true. It depends on what the record is, and what state you're in (aka: CONTEXT).

These two things mean the same thing. It's in the context - > it is not an inherent property.

It's not an inherent property - > it's not always present.

Some conclude therefore it shouldn't be an exception by default.

Re:You’re better off using Exceptions by horsawlarway on Monday February 03, 2020 @06:34PM (#22230580)
Ok, fair - I should have included the very next sentence in the quote as well, since OPs argument seems to be that missing records should NEVER cause exception:

>Anyone who expects a database to always have records and that the absence of a record is an "exception" has a very strange way of thinking.

But pedantics aside, my point stands. There are absolutely contexts and code paths where a missing record is basically unrecoverable. Why bother returning an error to the local calling context when you know that code doesn't make sense anymore and can't recover? A jump to a new code path is the right call, and exceptions do that (with a lot of nice trace information about why we ended up on that new code path to boot).

Doesn't mean a missing record should always result in an exception, but it's certainly not a "very strange way of thinking".

Re:You’re better off using Exceptions by takeda on Monday February 03, 2020 @11:56AM (#22226047)
It all depends on context. I believe that's why python for example throws an exception if given key doesn't exist when you use `dictionary[key]` but also gives you option to call `dictionary.get(key, [value])` which returns `None` or `value` (if specified) if the `key` doesn't exist.
Re:You’re better off using Exceptions by samatman on Monday February 03, 2020 @12:59PM (#22226898)
That one bites me when I've been away from Python for awhile. I prefer 'open' maps/dicts, where every key is valid and any unassigned value is None/nil.

I don't consider looking for an invalid key exceptional, basically, so I wish the syntaxes were reversed, so I could use the more succinct form for (my) more common case.

Re:You’re better off using Exceptions by loopz on Monday February 03, 2020 @04:19PM (#22229226)
Golang maps returns the value type's zero value in case the key doesn't exist: https://blog.golang.org/go-maps-in-action

The idiomatic way here being that the zero value should be a sane default for that value. You are then free to create your own types ontop of that, but the defaults are often in the ballpark of where you want to be unless you have specific needs in your context.

Re:You’re better off using Exceptions by r00fus on Monday February 03, 2020 @11:59AM (#22226077)
> If you expected the record to be found, the failure of finding it is an exception.

This is not always the case. In fact, for query APIs I do not expect it at all. Sometimes I'm doing something similar to a UPSERT operation with more nuanced behavior, then returning no existing entry on a preceding SELECT query could be the 99% use case.

Re:You’re better off using Exceptions by RHSeeger on Monday February 03, 2020 @12:08PM (#22226179)
>> If you expected the record to be found, the failure of finding it is an exception.

> This is not always the case. In fact, for query APIs I do not expect it at all.

And, in your case, "if you expected the record to be found" doesn't apply.

If I'm iterating over a list of names/id provided by the APi, and then calling the API for more information each one, then I would expect the record to be found... because the API just told me it exists. In that case, it not being found is an exceptional condition.

Re:You’re better off using Exceptions by Horusiath on Monday February 03, 2020 @12:45PM (#22226690)
Only if you're the only user of that API or these entities are eternal once created. In any application with multiple users it's a normal thing for system state to change between two API calls.
Re:You’re better off using Exceptions by weberc2 on Monday February 03, 2020 @11:59AM (#22226080)
The problem is that these systems are built in a way in which the data access latter is throwing the exception even though it can’t reasonably know if the record is expected to exist or not. It can’t or shouldn’t know that this is an invalid program state. Specifically, if exceptions are being used properly, you should almost never need to use try/catch.
Re:You’re better off using Exceptions by seanmcdirmid on Monday February 03, 2020 @12:25PM (#22226379)
Those are poorly designed APIs then. That is like having a dictionary that throws when a key isn't found but doesn't have an API for determining if a key exists or not.
Re:You’re better off using Exceptions by appleiigs on Monday February 03, 2020 @12:40PM (#22226623)
Yes, poorly designed API, but we still have to handle them and the world is filled with them. So you can have a structure that works for the real world, or you can have an ideological structure the stubbornly insists that you should know better. "bad programmer! you should know if the key exists or fail".
Re:You’re better off using Exceptions by seanmcdirmid on Monday February 03, 2020 @01:01PM (#22226932)
Poorly designed APIs provide little evidence on exceptions being bad or not since the APIs themselves have big problems.
Re:You’re better off using Exceptions by weberc2 on Monday February 03, 2020 @08:59PM (#22231603)
This thread is discussing whether exceptions are bad for handling unexceptional events. We are arguing that APIs that throw exceptions for valid program states, such as a missing key for some user input, is an abuse of exceptions. There are lots of these APIs in the world and we find that objectionable. You seem to agree with all of that, but you also present yourself as disagreeing with us, and it’s not at all clear what you’re disagreeing with specifically? Are you just being contrarian for its own sake or are we misunderstanding each other?
Re:You’re better off using Exceptions by weberc2 on Monday February 03, 2020 @07:28PM (#22230990)
It’s a poorly designed API, full stop. It doesn’t matter whether or not it has an API to check existence, it’s not the dictionary’s job to know whether or not a missing key is a valid state in the broader program, and most often it is. Moreover, it’s insane to do a separate “if exists” check every time you need some resource. And the world is littered with these poorly designed APIs, as they are idiomatic in Python, JS, C#, and Java.
Re:You’re better off using Exceptions by ProstetnicJeltz on Monday February 03, 2020 @12:05PM (#22226157)
We tried to use a result type in C# for cases like this. For example, we want to save an object, returning the updated object (on success), or an error on failure.

Unfortunately in static languages this leads to an unholy amount of boilerplate:

public Result<SomethingGood, SomethingBad> PerformUpdate(int goodThingId, UpdateForm form) { ... return new Result<SomethingGood, SomethingBad>(error); ... return new Result<SomethingGood, SomethingBad>(obj); }

The type annotations were hell. Sometimes there were three cases we wanted to consider. We went back to using exceptions, and are keeping a keen eye on the new C# features.

So ultimately - I agree with the author that throwing exceptions is fine, when things actually go wrong. It's also not that bad when things kinda went wrong, but sometimes the effort required to fix it isn't worth it.

Re:You’re better off using Exceptions by UK-Al05 on Monday February 03, 2020 @12:28PM (#22226453)
Frankly, that's because C# doesn't support proper discriminated unions in a concise way.

F# is a lot better at using result types. You don't even need to specify the return type.

Re:You’re better off using Exceptions by lllr_finger on Monday February 03, 2020 @12:28PM (#22226441)
It's been awhile since I've been in C#, but in other static languages like Rust and Kotlin with type inference, it would look more like:

public Result<SomethingGood, SomethingBad> PerformUpdate(int goodThingId, UpdateForm form) { ... return Err(error); ... return Ok(obj); }

which is considerably less boilerplate-y. When there are three cases you want to consider, that's no longer a sum type consisting of just success or failure - that's a different sum type. Maybe even represented as Result<ThreeCases, Error>.

Re:You’re better off using Exceptions by hn_acc_2 on Monday February 03, 2020 @11:53AM (#22225990)
Actually, I think exceptions are the clearest way to represent errors of any kind (reconcilable or not).

> A null value, a plain "error" object, or an error argument

In my mind, this just adds a lot more mental overhead while also being less informative than a simple exception. Plus you have to keep track of which method your current library has chosen to represent errors.

Note I am biased from using Python for a long time.

Re:You’re better off using Exceptions by mratsim on Monday February 03, 2020 @11:59AM (#22226078)
For me exceptions are for exceptional cases.

Any time you have user input, you can expect errors and so should have proper paths to handle file not found, invalid input, ... For those case, exceptions should not be used.

Re:You’re better off using Exceptions by hinkley on Monday February 03, 2020 @02:04PM (#22227670)
There are some areas of software design where essentially any strategy 'works' for a year and a half, or two years. If you come into a project you might not notice the friction caused by an arbitrary solution closer to when you are looking to move on than to when you arrived.

Testing is big this way, and I've had many 'discussions' with people who could demonstrate no experiences dealing with the consequences of their testing decisions two years on. Either they were gone or had externalized those consequences to others.

Getting multiple exceptions from multiple layers of the code only becomes problematic after the depth and breadth of the call tree has passed the point where a single developer can keep it all in their head.

Re:You’re better off using Exceptions by wvenable on Monday February 03, 2020 @11:52AM (#22225973)
Absolutely. Whether a method throws or not signals the intent of the code. In .NET, there are plenty of throwing and non-throwing versions of various methods. For example, there are both Parse() and TryParse() and also First() and FirstOrDefault() in Linq. Which method you use signals to the reader the expected result. If you're using Parse() then you're expecting the parse to succeed; Perhaps the data comes from a data file and if it's not an integer then something terrible has happened. Alternatively, you would use TryParse() for user input knowing that users will definitely not be trusted to always type a number.

Not having non-throwing versions of these methods (e.g. Java) means you lose the ability to signal intent and you have to do a lot of pointless catching of exceptions.

Re:You’re better off using Exceptions by TheSoftwareGuy on Monday February 03, 2020 @11:59AM (#22226079)
On the other hand, if you are writing library code or even a library-ish component of application code, having to write the same method a bunch of different times is tedious. Ideally, the language would be designed so that there is one sane way of propagating errors, which can be easily either handled or propogated.

I am quite a fan of Rust's solution, with Result<T> types and various macros/methods which can do the commmon stuff for you

Re:You’re better off using Exceptions by wvenable on Monday February 03, 2020 @12:38PM (#22226587)
In this case, it's the difference between what is an is not an error. Only one of those situations is an error.

I agree having to write the same method a bunch of times is tedious but that is usually not the case. Most situations have clear intentions. It's much more likely in framework APIs where there are a bunch of non-task-specific operations.

I find the whole manual propagation of errors, even with a lot of helpers, to just be tedious boilerplate. Most of the time I literally don't care about the error -- I want to crash my app, log the error, and alert me and the user. I don't need to propagate the potentially limitless number of errors possible in any non-trivial application.

Re:You’re better off using Exceptions by noisem4ker on Monday February 03, 2020 @02:24PM (#22227913)
In Java, you can obtain a throwing version of anything returning an Optional type:

Optional<Womp> getWomp() {...}

Womp womp = getWomp().orElseThrow();

Re:You’re better off using Exceptions by lenkite on Monday February 03, 2020 @12:16PM (#22226276)
I like the new style C++ FileSystem API's where you can either have an error code set or a thrown exception depending on the method overload you choose.

I like this a lot since generic utility methods can have use cases where you sometimes want an exception thrown or simply an error code returned.

If I am working in Java and a checked exception is thrown, my method usually allows the caller to supply an Function<UnderlyingException, DomainException> so that the caller can specify that a domain exception should be thrown instead of having to try-catch the thing.

But I agree with the author of the article - Exceptions are the right design technique when the caller considers an error as a failure as opposed to an unusual but handlable situation. Messing with Result in a deep call-stack is painful.

Re:You’re better off using Exceptions by baby on Monday February 03, 2020 @11:47AM (#22225916)
Actually, I’d argue that exception (that are caught) should only be used for recoverable errors. If you can’t recover, then you should crash.
Re:You’re better off using Exceptions by munificent on Monday February 03, 2020 @01:17PM (#22227148)
The great thing about exceptions is that they implement both of these behaviors with a single mechanism.

For recoverable errors, you catch.

For unrecoverable ones, you don't. The exception throwing mechanism unwinds the entire stack and crashes the app with a helpful stack trace.

Re:You’re better off using Exceptions by baby on Wednesday February 05, 2020 @01:29PM (#22249656)
True!
Re:You’re better off using Exceptions by yyhhsj0521 on Monday February 03, 2020 @11:46AM (#22225897)
The thing is that exception is as close as we get to pattern matching in many languages. When a language has even the most basic Either/Maybe/Option, you start to see fewer exceptions being thrown around.
Re:You’re better off using Exceptions by xeonoex on Monday February 03, 2020 @02:27PM (#22227946)
I think that's too simple of a case to really make an argument either way. Just return a Some/None or Optional. Null is ok too, but not the best (it's baked in to most languages already though). But at a higher level, if the program expected something, it may be an exception. Let's consider another case. What if you made the request and your session got terminated? That will be an exception too, and I don't think anyone will add that to the result type.

I feel like encapsulation means that functions often should throw errors, because the small, one responsibility functions shouldn't have knowledge of control flow. For example, division. Anytime you divide, you might try to divide by 0. That's an exception. The / operator returns a number or throws an exception. Who would use a TryDivide function? What would it solve? The same error might be an exception in one scope, and expected in another.

I get that exceptions can be expensive, but they should be rare. Saving time on the pre-check for an exception might save more time than the rare exception. I would never throw an exception strictly for control flow, but avoid exceptions is a bad idea IMO.

But the line is very blurry.

Re:You’re better off using Exceptions by dragonwriter on Monday February 03, 2020 @05:54PM (#22230270)
> For example, if a query is made to an API for a record and that record isn't found, the SDK wrapping that API would raise a "Record not found" exception. What the hell? A record not being found is a normal thing!

There are scenarios where it is and scenarios where it is not, it's fairly common for APIs to present both throwing and non-throwing variants (many languages stdlibs, for instance, provide both mechanisms for associative array lookups), and of course in any language with exception handling you can convert either to the other according to the needs of the consuming process at the point where you interface just by wrapping the finction in one which either throws or swallows the appropriate exceptions, depending on which direction you are converting.

Re:You’re better off using Exceptions by barrkel on Monday February 03, 2020 @12:08PM (#22226181)
You're right; if the only way to test for existence of something is to try and fetch it and check for an error state, then the API is forcing all the costs of its error handling on very regular uses.

And if you're dealing with non-determinism, then even a pair of APIs which let you separate out existence-checking from fetches isn't enough; you just introduce a race.

I like how .net does it with methods returning bool and an out parameter. Pattern matching on a return value would be fine too. It only makes sense on methods where you reasonably do need to handle the error case. And a variant which triggers an error condition on failure should exist too, for simpler programs which don't need to handle such failures, merely log them.

Re:You’re better off using Exceptions by hota_mazi on Monday February 03, 2020 @05:40PM (#22230132)
It's a pity they're called exceptions, they should be called errors.

Errors can be of two kinds: recoverable and unrecoverable.

Recoverable should be handled by checked exceptions and unrecoverable errors should be handled by runtime exceptions.

Re:You’re better off using Exceptions by naikrovek on Tuesday February 04, 2020 @10:36AM (#22236711)
> If I need an exception to be raised for this kind of thing, I'll do it myself.

This is the thing. This is the root of the thing. Let developers decide what's right for themselves. There are too many "me-too" developers writing terrible code according to terrible guidelines and terrible "best practices" (lol) and few people are actually thinking about what they're doing.

I agree with everything in your comment. Every single thing, and I wish more people understood your (our?) point of view.

Re:You’re better off using Exceptions by burtonator on Monday February 03, 2020 @12:21PM (#22226333)
The biggest issue I've seen with exceptions is that people bring up the issue when they are abused. I SORT of agree with you that an 'Record not found' exception is an abuse. This should probably be a null-object like an Optional ALA Java or Scala.

They are trying to avoid returning null in this scenario.

Unfortunately, if the API is designed poorly you're stuck with it.

I can sort of understand why people hate checked exceptions but working without exceptions is just terrible.

Re:You’re better off using Exceptions by jfengel on Monday February 03, 2020 @12:38PM (#22226603)
Nulls are also called the billion-dollar mistake (and that was decades ago; it's much more than that now). Both nulls and exceptions are ways of trying to make the main line of processing clear, while handling other lines in structured ways.

There's no one-size-fits-all solution. In a lot of ways, the best response to "record not found" is that you get the same result as finding one, except with zero answers. That means your main line can process the same way -- unless that doesn't produce the result you need. In which case maybe you an if(null) somewhere, or a special fake record, or an exception.

Re:You’re better off using Exceptions by aikah on Monday February 03, 2020 @12:57PM (#22226865)
> Nulls are also called the billion-dollar mistake (and that was decades ago; it's much more than that now). Both nulls and exceptions are ways of trying to make the main line of processing clear, while handling other lines in structured ways.

At the same time before NULL, devs used to use "guard values", so NULL is really just a convenience.

for instance, just to illustrate what I'm saying:

    let NULL = {} /* should every lib define its own null value? */

    function GetOneRecord(){
        let dbResult = queryRecordsFromDB();
        if (dbResult.length === 0){
            return NULL
        }
        return dbResult.records[0];
    }
Optional types, are better, but one needs functional programming features for it to be really useful.

What's people opinion on zero values by the way?

Re:You’re better off using Exceptions by loopz on Monday February 03, 2020 @04:41PM (#22229485)
Zero values may act as nice defaults. Programmers who care about their code, often want initial state or default state to reflect something useful. What zero value should reflect depends on context, but you get to state that once and for all, for that type. It's just one less thing off a mind when building code, although you'd want to catch any invalid usage. Ie. referencing zero value, could result in error if due to control flow, and panic() in case of programmer error. I don't think the language or library should choose for you, unless being bound by that is a very useful trade-off.
Re:You’re better off using Exceptions by Gibbon1 on Monday February 03, 2020 @01:03PM (#22226962)
Yeah the problem really is 'in band signaling' See SQL injection attacks for an another example why the practice is dodgy.
Re:You’re better off using Exceptions by detaro on Monday February 03, 2020 @01:01PM (#22226922)
What "functional programming features" does one need for useful optional types?
Re:You’re better off using Exceptions by kibwen on Monday February 03, 2020 @01:23PM (#22227203)
Putting aside the "functional" bit, for a language to allow user-defined (i.e. not hardcoded into the language itself (which may not necessarily be a bad thing, but that's beside the point here)) optional types, you'd want the ability to say "this variable is either _this_ XOR _this_" (a.k.a. tagged unions/sum types/what Rust calls "enums"), and then in a statically-typed language you'd additionally want generics.
Re:You’re better off using Exceptions by vraivroo on Monday February 03, 2020 @02:26PM (#22227942)
Null _pointers_ are called the billion-dollar mistake, not null values.
Re:You’re better off using Exceptions by z3t4 on Monday February 03, 2020 @06:21PM (#22230485)
The slow, stupid, and impractical way is to first ask if any records exist, before asking for the records. Remember that computers are dumb, but they are also fast. Asking for the records without first asking if they exist is an optimization. The records might exist when you ask if they exist, but then they might be gone when you ask for the actual records, now that would be an error.
Re:You’re better off using Exceptions by shawnz on Monday February 03, 2020 @11:59AM (#22226071)
Your example is a good argument for using null or empty list in situations where that is applicable, but it doesn't explain why a custom error object or callback would be better than using an exception, even in reconcilable scenarios. In fact I think using a custom error object would go against your general point of taking advantage of preexisting language features where possible.
Re:You’re better off using Exceptions by dahfizz on Monday February 03, 2020 @12:43PM (#22226673)
The usefulness of exceptions in the cases you present is to force the developer to handle the cases where things go wrong, such as no records are found.

There are more clever ways to do this nowadays with monadic Result types, but the core idea of forcing a developer to handle error conditions is useful in API design.

Re:You’re better off using Exceptions by mrec on Monday February 03, 2020 @12:59PM (#22226907)
Isn't that "forcing a developer to handle error conditions" only true of Java-style checked exceptions, though? I'm not aware of any non-JVM languages taking that route, even the very Java-clone-y C#, and thought it was widely believed to have been a mistake.
Re:You’re better off using Exceptions by interlocutor on Monday February 03, 2020 @01:34PM (#22227327)
Unchecked exceptions are a disaster. In C# when you call a method you have no idea what exceptions can be thrown by the called method unless you inspect the called method and all the methods called by it. The called method can be modified at any time and a new exception can be thrown and your code will compile just fine. This is bad because the new exception may be a recoverable condition and instead of recovering your program will crash. This is why exceptions that can be thrown by a method should be considered part of the signature of the method and you should get a compile-time error (as opposed to a runtime crash) if the method throws a new exception that wasn't there when you originally wrote the code.
Re:You’re better off using Exceptions by jcranmer on Monday February 03, 2020 @02:30PM (#22227996)
As my opinions on exceptions have evolved throughout the years, I've come to think that there is value to unchecked exceptions, but unchecked exceptions need a fundamentally different mode from checked exceptions.

The best motivation for unchecked exceptions are things like division by 0, or null pointer dereferences: these are things that result from programmers misusing the API, and are generally unrecoverable. What you want instead is some sort of "graceful crash"--for example, if you're a web server, display a 500 page and log the stack trace somewhere internally. Using a pretty distinct mechanism for driving these error cases (e.g., Rust's panic mechanism) I think works better for emphasizing the crash aspect here.

Of course, now you have the regular checked exceptions which are a fundamental part of the function type. It's not clear to me that the try/catch/throw model is necessarily the best model for propagating these exceptions, and there are several cases where the overhead involved in the (misleadingly named) zero-cost exception handling model are not appropriate for the model.

Although there is something to be said for easy upgrading of checked into unchecked exceptions. It's a relatively natural assertion that something can't fail for reasons the compiler doesn't understand (which means informing the programmer when and where it failed is very critical!). I've always been annoyed by Eclipse deciding that the default implementation of catch should be "ignore the exception" instead of "wrap it in a RuntimeException."

Re:You’re better off using Exceptions by mrec on Monday February 03, 2020 @02:08PM (#22227721)
> In C# when you call a method you have no idea what exceptions can be thrown

Well, you have no idea in Java either, given that unchecked exceptions exist.

I understand the goal of checked exceptions, I just haven't found much value in them in practice, and given that nobody has copied them I don't think I'm alone. I'm sure it depends what area you're working in, but in my experience it's rare (not unknown, but rare) to be able to do much with e.g. an `IOException` at the call site, and naive approaches like automatic retry can easily be worse than crashing if those retries end up looping excessively and spamming a resource that was already struggling.

My personal preference is for non-exception mechanisms (Maybe/Option/Result objects, or C#'s TryXXX methods) to handle recoverable cases, and unchecked exceptions with very high-level catchers to convert the nonrecoverable ones into sensible diagnostics. YMMV, obviously.

Re:You’re better off using Exceptions by _ZeD_ on Monday February 03, 2020 @01:20PM (#22227175)
Still some people like me think that checked exception are the damn right way to express the possible outcome of a function. Every time I need to work with C# / python I need to play "catch" to keep track of all the possible exceptions that could be thrown at any function call...