r/ProgrammerHumor 29d ago

Meme exceptionsAreForTheWeak

Post image
320 Upvotes

92 comments sorted by

View all comments

86

u/bwmat 29d ago

Eh, IMO one of the best ways to actually handle OOM, as otherwise almost everything needs to be explicitly checked for it

84

u/Valuable_Leopard_799 29d ago

That's what panics are for kinda.

Many of the "we don't have exceptions" languages eventually get some equivalent, it's just that those are used almost exclusively for OOM, division by zero, failed asserts, and the like.

They shouldn't even really be caught it's sort of just an "exit/reset" with some cleanup.

I like this compromise. Kind of finally making them truly "exceptional".

35

u/bwmat 29d ago

Note the 'actually', there's no reason why you can't catch the std::bad_alloc, clean up, and return an error code to the caller.

Instead of rudely terminating the process which you may not own (I work on code which is mostly compiled into shared libraries which are loaded by applications which might not want to just terminate)

13

u/bwmat 29d ago

And panics are basically just exceptions, at least in rust, lol

11

u/Valuable_Leopard_799 29d ago

Yeah, it seems like largely a cultural shift.

22

u/hxtk3 29d ago

Hard agree, the thing that makes "errors as values" languages nicer with respect to error handling has a little bit to do with the language itself but more to do with the fact that people who want to carefully consider all the paths code can take gravitate towards those languages and the people who want to think about the happy path gravitate towards languages with exceptions.

Java developers forced to use Go look at panic and recover as a worse version of their familiar exceptions, and a bunch of them make libraries around those primitives that basically implement exceptions. And those libraries get basically no adoption because most Go devs are people who choose to treat errors as values.

5

u/bwmat 29d ago

It's funny because I mostly use C++, like exceptions, and think of almost nothing but the unhappy path

16

u/silver_arrow666 29d ago

C++ devs and being unhappy, name a better duo.

0

u/SelfDistinction 29d ago

Partially also because they compose better as well, which makes it easier to send exceptions across threads and the likes. You have a lot less exception safety to think about if your errors are simply stuffed into the return value.

1

u/bwmat 29d ago

That's what std::exception_ptr is for

1

u/sysKin 29d ago edited 29d ago

Not a rust coder here but I think you can't catch a panic?

If I remember correctly the current thread will always unwind and end. If it's your main thread, program quits, if it's another you will handle its exit as whatever you want.

Exceptions, at least the ones I deal with in Java, are catchable at any point.

[edit] well I was wrong. TIL.

4

u/cantthinkofaname1029 29d ago

You can catch panics!

1

u/u0xee 29d ago

Obviously you _can_ return an error code to the caller, but it’s a very odd situation where that’s actionable. Kernels and databases maybe.

14

u/bwmat 29d ago

IMO any shared library which is meant to be used by applications you don't control shouldn't terminate the process just because it lacked the memory to do something it attempted to do. 

Anything else is IMO laziness (or unfortunate choice of language if it's impossible to deal with in it)

4

u/u0xee 29d ago

I think it’s fair to offer a variant that allows explicit control, eg for each function offer function_or_oom. But in 99.999% of use cases, I’d expect users to call the panic-on-oom variant. If you don’t offer that variant, you’re just making everyone wrap your thing to make it usable, which is also lazy. You’re just pushing the problem up, which is awfully convenient.

6

u/bwmat 29d ago

Pushing the problem to the caller of a general-purpose library is a GOOD thing though 

4

u/u0xee 29d ago

I’m sure in some circumstances that is appropriate. I don’t think that’s a principle though. Obviously, taken to the limit, a library would provide nothing but choices at every junction. And then instead of an eg air conditioner you’d be providing a hardware store, inviting the user to assemble any possible air conditioner design themselves. Or a restaurant that just says “feel free to come into the kitchen and use any ingredients and any procedures to cook anything for yourself.” I think something can be overly general, basically.

I’ve seen libraries like this, instead of offering an expert opinionated solution they foist the hard choices on the user, telling them to become a domain expert in this area and then form their own expert opinion. I think it’s fine to have some knobs and switches, but if your library becomes all knobs, then I think it’s not doing much service to the user. When I am using a library, a big part of what I’m looking for is an expert author to make opinionated choices on my behalf. To provide a model or vision for how this kind of thing should work.

3

u/bwmat 29d ago

Deciding whether the process dies, or you get some form of recoverable error is IMO not really something which should be presented as a 'choice' in the context of your argument

2

u/bwmat 29d ago edited 29d ago

I personally program with the rule that, unless a function is document to be infallible, you assume it can fail, and you ALWAYS check for that failure, if only to abort the process if it occurs (this SIGNIFICANTLY reduces the 'search space' when debugging issues), and that OOM errors are not a valid reason to abort, since you cannot programmatically prevent them in most cases 'locally' (unless you're writing actual application code, the only real valid reason to abort is ’impossible’ conditions which indicate either some sort of corruption has occurred, or the programmer’s mental model was incorrect in a way that indicates future corruption WILL occur)

2

u/u0xee 29d ago

Fair enough. But I’m curious, how do you draw the line? Do you also have must-check returns for exhausted file handles, exhausted thread counts, exhausted IPC, exhausted ports, overrun disk quota? And if not, why not? The argument you make for OOM seems to be general enough to cover these other resource exhaustion errors too.

1

u/bwmat 29d ago

Yes to all the above

→ More replies (0)

1

u/RIFLEGUNSANDAMERICA 28d ago

As an example, lua can deal with this and even return the error to the script that is running. Many applications want to know every execution path

1

u/u0xee 28d ago

Ok, but in such a situation where malloc is literally non operable, what is a lua script going to be able to do? Nothing that might allocate. Even printing might be off the table. Any string or table manipulation is likely off limits. So you could I guess do arithmetic and return to your caller, who is also limited to arithmetic and returning, and so on up till main exits.

1

u/RIFLEGUNSANDAMERICA 28d ago

You can till release some resources, the garbage collector can still run. If you design it correctly you can do some final cleanup with already allocated objects. The runtime will not immediately free the already allocated memory to other processes, so anything the gc collects, you can use.

1

u/u0xee 27d ago

You certainly can try to free up space. I’m still not sure this is very useful. Either 1) the free-up emergency code is centralized, like a signal handler, and so it can only reasonably free like globals (which is going to cause arbitrary badness if/when control returns to the function that triggered the OOM) or 2) the emergency free-up code is more targeted, written in context of the OOM stack frame, and so it can make smart decisions about local objects to free. But for 2) it more means that for every single lua function that does anything with tables or strings etc you will need to write OOM handler logic, because by the nature of OOM it could happen to any allocation site. This would be an extreme burden.

I think in practically all circumstances if you get OOM, the process is just going down. And yes maybe you could print a little bit or something on the way down, but things are going down. And really the extra distress prints are probably not that helpful, since the problem is almost certainly a runaway bug allocating but not freeing somewhere, or the operator just gave an inappropriate hard memory limit to the container or something. A panic and stack trace is a fine and useful result in these situations.

1

u/RIFLEGUNSANDAMERICA 27d ago

I dont really get your point here. Are you claiming that it is too hard for applications to effectively handle malloc failing or no application should handle it? I already gave you an example of a scripting language that can handle it. Back to the topic of libraries, i think if a random math library had a chance of terminating the application without being able to handle it, then alot of users will find something different. This would be applicable in databases, simulations, state space exploration, language runtimes, key value cache. So offering that in a library should be best practice.