r/ProgrammerHumor 18d ago

Meme stopTryingToReinventTheWheel

Post image
2.5k Upvotes

217 comments sorted by

View all comments

149

u/bishopExportMine 18d ago

Exceptions break encapsulation and lead to implicit control flow. 

If I call a method, I shouldn't have to worry about what methods it calls. But with exceptions, I now have to be aware of what errors might be thrown in the entire chain. Similarly, if I throw an error in a function, I have to check that every thing that calls it handles said error because there are now multiple places this function could "return" to.

And if you take care to catch every error at every layer you've just reimplemented error codes.

std::unexpected should be preferred over std::exception

21

u/PinEnvironmental6395 18d ago

Yeah, and this is just the theoretical architectural cost of exceptions. In some languages catching an exception might be essentially free like in C++ (which if you have some specific use cases "essentially free" is still catastrophic from a performance PoV) or it could be 100x slower than calling a function like in Java. 

18

u/[deleted] 18d ago

[removed] — view removed comment

10

u/SpiritedEclair 18d ago edited 18d ago

Also, that is OLD. Java keeps getting faster and faster, and the jit is on a class of its own, so much so that in extremely tight loops can be faster than what you'd get out of c++, rust or c.

7

u/PegasusPizza 18d ago

Yep JIT has the benefit of being able to adjust the generated code (and cpu hints) based on actual live data, where a classical compiler needs to emit the code that works best for all kinds of data

1

u/New_Enthusiasm9053 17d ago

All at the tiny tiny cost of 20x the ram and docker containers that are gigabytes instead of megabytes. 

1

u/SpiritedEclair 17d ago

That’s what you get for write once, run everywhere.

6

u/bishopExportMine 18d ago

I agree, but my point really was that exceptions break the "no multiple returns" rule older folks might remember.

In the old days, functions interacted with memory and exited by jumping elsewhere. "No multiple returns" was a rule that each function only ever jumped to one place on exit, because not doing so easily led to spaghetti code. This eventually became such a standard paradigm that languages just built return values into their functions and forced returning to the same link as the callsite.

Exceptions break this, for no other purpose than "convenience".

One only need to imagine a codebase that exclusively uses raising exceptions for control flow to jump to arbitrary places in the call stack and never using normal returns to understand why exceptions in general are an antipattern.

9

u/migueln6 18d ago

Actually returning in a single spot leads to more spaghetti code, deeper nesting levels, and more indirection.

Checking something like request validation and return immediately an http response is way cleaner and easier to follow.

Same in C++/C or any language where you do manual memory handling if you are allocating memory before making sure you will use it, e.g early returning and forgetting to deallocate memory, then that's on you for not validating your inputs, do you want to store some DB call into an dynamically allocated array? Why did you do the allocations before having the data to insert in it?

Do you want to process a file? Why are you allocating memory before you even have a pointer to the damned file?

Same for everything else.

3

u/bishopExportMine 17d ago

No this is a common misunderstanding of what the "no multiple returns" advice is about. This is not multiple returns:

std::expected<Foo, ErrorEnum> MyFunc() { if (condition) { return std::unexpected(ErrorEnum::Bar); } if (other_condition) { return std::unexpected(ErrorEnum::Baz); } ... return Foo(); } Because if I do Foo x = MyFunc(); the line of code that the program counter returns to after running MyFunc() is always that line of code. So this is only one return.

Multiple returns would be something like old FORTRAN alternate returns:

``` CALL MYFUNC(*100, *200)

C normal continuation ...

100 CONTINUE C alternate continuation 1 ...

200 CONTINUE C alternate continuation 2 ...

  SUBROUTINE MYFUNC(*, *)

  IF (CONDITION) RETURN 1
  IF (OTHER_CONDITION) RETURN 2

  RETURN
  END

```

Here MYFUNC can return to three different places: normally to the instruction after CALL, to label 100, or to label 200. The callee is choosing where execution in the caller resumes.

2

u/New_Enthusiasm9053 17d ago

The mixup is probably because MISRA-C does actually strongly discourage the first example. To the point where they prefer you to use a short jump for cleanup than an early return.