C++ Logo

std-proposals

Advanced search

Re: [std-proposals] fine-control exception/error/UB handling on function boundary

From: Tiago Freire <tmiguelf_at_[hidden]>
Date: Fri, 28 Aug 2026 18:52:54 +0000

> If a function already throws an exception, does this matter what new type it throws for the whole call stack?
> Only place where it matters is the place where you handle this new exception, rest code should stay agnostic to this new error case.

Yes, it does matter. How else are you going to find out the "Only place[s] where you handle this new exception"?
That's a much harder problem with exceptions than just looking up who is calling your function.

> Error codes are the same

They most certainly are not. The day you find a function were adding an error code silently adds a new return type to the caller without so much as a warning, is the day I will quit programming.

> Error codes are the same, if you need to add failable operation to any function you need to add propagation of failure upstream.

Do you?

> If the function returns `void` you need to change it to return some error code.

Yes!
And the problem is?
You changed the contract. Something that used to not fail, now does. If the code was not prepared to handle that, it should fail to compile and force you to fix the caller.
I don't see "having to do more work to fix other places because the interface has changed" as a problem, the problem is having to do all that and not know, and bugs are created and left to rot your code base.
That's why I think it would be amazing in code bases that used exceptions if functions were forced to document what exceptions they could throw. You would "catch" the problem immediately instead of staying undiscovered until one day they come to bite you.


> Even better if you have robust error codes of 20 diffrent values and add some C code that has its own error codes how do you map both? Do you glue them together?

Are you making an argument for return codes? If function X returns an error code in the standard A, but it calls function Y that returns an error code in standard B, if Y adds a new error to B, and X wants to propagate that extra detail to the caller then it must have to convert it to standard A, so that the caller of X only ever has to deal with errors in standard A.
Exceptions is where you have to deal with the mess of having to deal with errors in standard A and standard B, or whatever C D or E may occur in the future, which you have no way to know because the interface doesn't document that.

You wouldn't do this:
```expected_variant<int, ErrorA, ErrorB, ErrorC> Foo(); ```

You just do this:
```expected_variant<int, ErrorA> Foo(); ```
ever

But
```int Foo() throw(ErrorA, ErrorB, ErrorC); ```
Is what you get with exceptions, because the caller doesn't have to deal with the exceptions.
But it is made much worse if you do this:
```int Foo(); ```
You have to catch ErrorA, ErrorB, and ErrorC, but it doesn't tell you.

Do you see the problem?


-----Original Message-----
From: Marcin Jaczewski <marcinjaczewski86_at_gmail.com>
Sent: Friday, August 28, 2026 20:02
To: std-proposals_at_lists.isocpp.org
Cc: Henry Miller <hank_at_millerfarm.com>; Tiago Freire <tmiguelf_at_hotmail.com>; Zamfir Yonchev <zamfir.yonchev_at_gmail.com>
Subject: Re: [std-proposals] fine-control exception/error/UB handling on function boundary

pt., 28 sie 2026 o 18:33 Tiago Freire via Std-Proposals <std-proposals_at_lists.isocpp.org> napisaƂ(a):
>
> > the real problem is as soon as you make that change you have often thousands of functions that cascading need to change because now you changed your interface.
>
> Yes, but isn't that just the symptom of a much larger problem.
> You haven't as much provided a useful function as you have provided a means for your application to ungracefully terminate if you don't document that your code can throw, what it can throw and how you can recover if a function does throw. I.e. you just gave everyone a loaded foot gun.
>
> If you state that your function can throw A, B, and C I can write a catch clause to catch A, B, and C and *handle the error*.
> But now you if you make a change and it can also throw D, the fact that this cascades trough out your entire code base is a good thing.
> You have changed the contract of what the function can do, code that was previously safe now isn't, and if the caller doesn't catch it you have also changed the caller's contract, then the caller of the caller will throw an additional exception as well.
>

If a function already throws an exception, does this matter what new type it throws for the whole call stack?
Only place where it matters is the place where you handle this new exception, rest code should stay agnostic to this new error case.

> Exceptions are evil because it changes code upstream instead of downstream.
>

Error codes are the same, if you need to add failable operation to any function you need to add propagation of failure upstream.
If the function returns `void` you need to change it to return some error code. If it's already return some error code you need extend it to add new value and handle it upstream. Even better if you have robust error codes of 20 diffrent values and add some C code that has its own error codes how do you map both? Do you glue them together? Even is only place where this can happen?

Only way to handle it generally is code like:

```
expected_variant<int, ErrorA, ErrorB, ErrorC> Foo(); ```

That have exactly same problems as

```
int Foo() throw(ErrorA, ErrorB, ErrorC); ```



> The fact that you have to deal with changing code in a thousand different places throughout the code base, is a small mercy that allows you the opportunity to at least validate if code upstream was able to handle it.
> Make that change silent and you have not fixed the problem, you just hid it and don't realize you created a problem, now you have thousands of different bugs with a single code change.
>
> That's why I'm in the camp "No exceptions" please!
>
> -----Original Message-----
> From: Henry Miller <hank_at_[hidden]>
> Sent: Friday, August 28, 2026 14:21
> To: Henry Miller via Std-Proposals <std-proposals_at_lists.isocpp.org>
> Cc: Tiago Freire <tmiguelf_at_hotmail.com>; Zamfir Yonchev
> <zamfir.yonchev_at_gmail.com>
> Subject: Re: [std-proposals] fine-control exception/error/UB handling
> on function boundary
>
>
> On Fri, Aug 28, 2026, at 03:38, Tiago Freire via Std-Proposals wrote:
>
> > And I would kill to be able to specify a list of possible exceptions
> > at the interference level to be able to validate the code is
> > exception safe.
> >
>
> A number of languages have tried that in the past and books have always quickly come up and said, never specify the exact exceptions except on a very generic level. That is, you say, 'throws anything' in whatever the language syntax specifies that as. Too many times you want to make a slight change to implementation and discover that it would really be helpful to throw a different exception in some situation. Often some users are demanding a specific bit of information that they would catch and handle differently. the real problem is as soon as you make that change you have often thousands of functions that cascading need to change because now you changed your interface. You can throw a clang tidy at the problem but that's not going to tell you the place where you should catch the exception in cases where you don't want to cascade it all the way and so it's a question of valuable even with modern tools.
>
> Now in C++ it would be useful to say throws std::exception, that is I won't throw an int or any other type that is not derived from standard exception. This is good practice anyway. It might be useful to also say, we'll not throw std::bad_alloc or something like that, where you can say a whole class of things would not be thrown.
>
> Though I'm not sure if there's any advantage to putting the above into the language versus putting it into something like the doxygen comments. I'm not sure if the compilers can use it and so long as the information of what your wheeler will throw is in place, static analysis can find it, that's probably good enough for your needs.
>
> however specific list of exceptions that a function will throw is
> always going to be listed in every intelligent style guide we will not
> use this
> --
> Std-Proposals mailing list
> Std-Proposals_at_lists.isocpp.org
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

Received on 2026-08-28 18:53:02