News for hackers. Stuff that matters.
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.