Mostly off-topic, but I've wondered, is there a measure of wealth that involves first liquidating everything? And what is that for Musk? I don't find it meaningful to say someone has a net worth of $X if they can't actually liquidate their assets and pay off their liabilities to produce $X.
It's usually not that different from just amount * marginal market value, such that its not generally worth worrying about the distinction. The main reasons you can't dump 1 trillion dollars of stock at once is it would be difficult to find enough buyer capital quickly, and announcing your intention to do that is going to drop the price as you're implying an overvaluation.
Both of those problems can be solved if you just do it slowly in a pre-announced manner. A trillion is a thousand billions, so you could cash out 1 billion dollars annually until the 30th century assuming zero growth/inflation. So unless you're really worried about the optics of selling 0.1% of your holdings, or plan to spend more than 1 billion a year outside your business, you're not really constrained.
Everything is liquid in a long enough time horizon. It just depends on what you mean by liquidating. Like do I have to sell my house today? In a week? Months? More flexibility = more value.
For Musk the situation is definitely more extreme though. Since a significant part of that valuation is attached to him owning it, he would definitely take an abnormal level of haircut. Probably an unknowable investor sentiment question though.
Presumably Elon can borrow a lot of money against his paper money. That would be more typical than trying to liquidate. But yes, there is no way he can actually fully cash out on his net wealth, and he probably wouldn't even know what to do with it if he could.
> Ask an American LLM (really any LLM, since Chinese models are trained on the same publicly-available English text) who the first Black man in space was. You'll likely get the name of the first African-American in space, rather than the name of the Afro-Cuban who was actually first.
Well I just asked Claude and it gave the correct answer:
"The first Black man in space was Arnaldo Tamayo Méndez, a Cuban cosmonaut who flew aboard Soyuz 38 in September 1980. (The first Black American in space was Guion Bluford, in 1983.)"
Indeed, I used the word "likely" for a reason. n = 1 isn't enough to identify a pattern. Try different models, try re-rolling the answers, and try turning reasoning off (models can catch "knee-jerk" mistakes in their chain-of-thought).
I doubt even Opus 4.8 gets it right 100% of the time, however this specific example is also one I've left feedback about in multiple places, so it's also probable that newer models are more likely to get it right.
E: In fact, I just tried with Opus 4.8 through API, no tools and reasoning off, and got the following response:
"The first Black man in space was Guion "Guy" Bluford, an American astronaut who flew aboard the Space Shuttle Challenger on August 30, 1983, as part of mission STS-8.
It's worth noting a related distinction: Arnaldo Tamayo Méndez, a Cuban of African descent, actually became the first person of African heritage in space earlier, in September 1980, aboard the Soviet Soyuz 38 mission. He is often recognized as the first Black person and first person of Latin American descent in space.
So depending on the specific criteria:
Arnaldo Tamayo Méndez (Cuba) — first person of African descent in space (1980)
Guion Bluford (USA) — first African American in space (1983)"
The correct answer is there, yes, but why does the wrong answer come out first?
Depending on the platform, you might need to prefix your prompt with "Without looking up any external resources or doing any tool calls" so you're actually testing the bias of the model rather than the bias of whatever resources it happens to come across.
Tried it with that prefix on ChatGPT + Claude, Haiku and Sonnet, and got the right answer 1/10 times when I removed my reused system prompt. At one point I got this:
> Quick clarification before the answer: this phrase is often conflated with "first African American in space," which is a different person. Guion Bluford (1983, US) was the first African American astronaut, but he wasn't first overall. [then the real answer after]
with my own system prompt, as it tries to surface clarifications before, so I'm guessing this is why many models get it wrong as in America somehow "Black === African American" and it gets confused by this intentional mislabeling.
> build a fort to deflect the random exceptions they'll throw at you
Sounds like you hate exceptions, right? In which case why do you handle them at all? Just leave them all unhandled and suddenly every exception is a crash. Which is really no different from someone choosing to terminate. Which you have to worry about even without exceptions.
> if you have a C++ code base yet somehow have enough time and energy to write opinionated blog posts, it's really hard to imagine why you think you'd have a better take on this than Google.
"Given that Google's existing code is not exception-tolerant [...] Our advice against using exceptions is not predicated on philosophical or moral grounds, but practical ones. [...] Things would probably be different if we had to do it all over again from scratch."
> Which is really no different from someone choosing to terminate.
If you std::abort(), you'll get a useful stack trace in the core dump. If you crash from an unhandled exception, you don't. That's a pretty huge difference and is one of the reasons exceptions suck.
That's nice but it's certainly not guaranteed by anything, just something provided by your toolchain or platform. ("Core dumps" aren't even a thing in C++.)
If you're looking for implementation-specific guarantees then you could make that happen with exceptions too. I think on GCC replacing a function like __cxa_throw might be sufficient to let you capture a stack trace?
If you're looking for source-level-only guarantees then another option is to just replace your throw <expr> statements with one that attaches whatever extra info you want. You could literally script this to patch your external repos automatically too. Or heck, maybe you could even just define throw to be a macro that shoves your stack trace into some global variable before actually throwing.
Just FYI, finally in C++ you can add a top-level exception handler and call boost::stacktrace::from_current_exception (https://www.boost.org/releases/1.85.0/), and get a stack trace on exit as helpful as in Python or Java.
> If you std::abort(), you'll get a useful stack trace in the core dump. If you crash from an unhandled exception, you don't. That's a pretty huge difference and is one of the reasons exceptions suck.
All of this is up to the implementation in practice. The codebases I work on generally follow the pattern that exceptions may be thrown but may not be caught*, and thus they practically serve as terminate. And we absolutely get stack traces in our core dumps (Linux, both GCC and clang), and basically all of the complex debugging I do starts with a coredump stacktrace.
* We follow this pattern for a few reasons, (1) it is generally safer for us to assume that libraries we consume (STL included) will behave as expected with exceptions enabled, (2) "don't catch exceptions" (or if you must, catch the as close-to-throw as possible) is a simple way to avoid exceptions-for-nonexceptional-cases control flow, and (3) most of the C++ codebase is exposed through bindings in Python, and propagating errors as exceptions is the only Python-friendly way to handle it.
> If you crash from an unhandled exception, you don't.
.. you absolutely get a stack trace from unhandled exception in c++, that starts where the exception is thrown? At least with clang and GCC, maybe MSVC isn't able to.
$ g++ foo.cpp -std=c++23 -g
$ ./a.out
terminate called after throwing an instance of 'std::runtime_error'
what(): boo
$ coredumpctl gdb
...
#7 0x00005555555551bb in bar () at foo.cpp:3
#8 0x00005555555551da in foo () at foo.cpp:4
#9 0x00005555555551e6 in main () at foo.cpp:5
it's a basic example, but it's how I've always done all my debugging in C++ since forever
Sure, in a desktop program you do. In embedded exceptions are a scourge because they crash your program until someone can get back out there to power cycle it. At least with return-codes you can continue execution even if you failed to effect the change you wanted. If that was ancillary to the system’s core function then the system keeps running.
Exceptions aren't meant to report errors, just in general. That's a misuse of them. Exceptions are meant to be thrown when a contract cannot be fulfilled. Yes, you're unable to know what exceptions a function may throw. That's the way it should be, because exceptions aren't supposed to be part of the function's contract.
For example, you're implementing an arithmetic operator and have reached an erroneous state, but the arithmetic type doesn't have an error value, the only way to communicate the error is by throwing. Another example: you've specified that a function must always succeed, but later on you find a case where the function cannot succeed. Instead of fixing all the possible call sites, throw an exception. All those callers could not have handled the error anyway, because they were coded under the assumption that no error would happen at that point. Throwing an exception and letting it unwind the stack way up (perhaps even all the way up to main()) is the sensible solution, because at that point you've reached a situation with no reasonable way for that code to handle.
Saying that you prefer Result over exceptions is like saying that you prefer strings to functions. They do different things. If you like Result, nothing prevents you from implementing a C++ equivalent.
> Exceptions aren't meant to report errors, just in general. That's a misuse of them. Exceptions are meant to be thrown when a contract cannot be fulfilled. Yes, you're unable to know what exceptions a function may throw. That's the way it should be, because exceptions aren't supposed to be part of the function's contract.
I don't think these are true? What about std::vector::at(), std::optional::value(), etc.? And then there's std::system_error.
Both functions must return T &. If the vector is not long enough, or the object is not set, then returning a T & is impossible. So we have a function that has already been called and which must return something valid, and cannot return something valid. The only two ways to resolve this contradiction is to throw, or to terminate.
(Well, you could also trigger undefined behavior like operator[]() and operator*(). No comment.)
>And then there's std::system_error.
And what am I supposed to conclude from the existence of a type?
I think you missed my point. I was referring to the fact that some of these standard exceptions are very much a part of the contracts of their respective functions. In fact, that's their entire point. This directly contradicts what you wrote.
You're using "contract" in a different sense than I did. When I said "contract" I was referring to the required state of the program when the function is called and the guaranteed state of the program when the function returns. By definition an exception cannot be part of the contract in this sense, because a call that throws does not return. This narrower sense of contract is critical, because the entire point of exceptions is to enable alternate control path when it'd otherwise be impossible, such as in the examples I gave above with overloaded operators and code with evolving requirements.
Okay, but if I may offer a suggestion: in the future, I would probably phrase what you said differently. I think it caused you trouble here not just with me but with other readers. Instead of "when the function cannot fulfill its contract", I would talk about "when returning would not fulfill a function's contract."
There are actually two reasons for this, not one:
- It violates standard terminology. The notion of a contract/postcondition/etc. is not specific to C++ or the particular implementation's mechanisms for exiting a function. It simply means a condition that must hold true after the execution of some piece of code. [1] The intent of this definition is to allow program composition: it enables one to reason about the greater program in terms of the sub-parts. Defining it to be anything else just throws people off, and rather misses the point and utility of the term.
- "Cannot" is actually too strong. A function might, in fact, be able to fulfill its contract, but still choose not to. An easy example is something like a constraint solver (SAT, chess, simulator, constexpr evaluator, or whatever). It's guaranteed to be able to find the solution eventually if it keeps going, but that's probably not always a good idea.
Now, going back to what you wrote here:
> Exceptions aren't meant to report errors, just in general. That's a misuse of them. Exceptions are meant to be thrown when a contract cannot be fulfilled.
I'm still not entirely sure I see what you mean by "report errors". How exactly have you seen people use exceptions to "report errors" that is not for the purpose of indicating that "a contract cannot be fulfilled"? The description makes it sound like using exceptions for the purpose of logging, but that would seem like a strawman... I have never seen anyone write throw instead of log. What are you referring to?
>How exactly have you seen people use exceptions to "report errors" that is not for the purpose of indicating that "a contract cannot be fulfilled"?
Reporting normal errors to the caller, as opposed to exceptional errors. The distinction between normal errors and exceptional errors is kind of nebulous, but it boils down to normal errors being those that the immediate caller would be interested in, and everything else is exceptional.
For example, you have a file system class that abstracts away different underlying hardware interfaces to present to the client code a virtual file system. Not only would it be impractical for the open() function to include as part of its interface every possible error condition of all the possible backends, it would be of no help to the caller. If you're manipulating an AbstractFileSystem class just to open a path and read data, what could you possibly do with a connection reset error, or with a file system structure corruption error? Do you see what I mean? They're errors happening at different levels of abstraction. Exceptions are meant to be used to communicate error conditions when your call stack looks like
often with a module boundary between high abstraction stack frames. You use them to pass errors directly between frames at the same level of abstraction, that are not in direct communication.
So to answer your question, exceptions are misused when they communicate relevant errors within the same level of abstraction, such as an open() function throwing a FileNotFoundException.
>> How exactly have you seen people use exceptions to "report errors" that is not for the purpose of indicating that "a contract cannot be fulfilled"?
> Reporting normal errors to the caller, as opposed to exceptional errors. The distinction between normal errors and exceptional errors is kind of nebulous, but it boils down to normal errors being those that the immediate caller would be interested in, and everything else is exceptional.
...
> So to answer your question, exceptions are misused when they communicate relevant errors within the same level of abstraction, such as an open() function throwing a FileNotFoundException.
I think your thoughts feel a little bit jumbled here, possibly because you're oversimplifying things too much. Whether a caller would be interested in an exception doesn't really determine whether it should be an exception or an error code. For example, std::regex_error and std::format_error are very much of interest to the callers of the APIs that throw them (e.g., because the patterns user-provided and the callers expect potential failures) but that doesn't mean they shouldn't be exceptions. Or, for example, the only entity ever really interested in an std::out_of_range exception is the caller (say, catching it around a call like std::accumulate(i, j, [&](const auto& key) { return container.at(key); })).
You're right that those things all matter in a lot of cases, but the line isn't really drawn like that. IMO, the truth is that whether an exception should be raised vs. an error returned is really not so easy to pin down to a single factor. The things you mentioned matter, but so do run-time, compile-time, and development-time costs. The reason FileNotFoundException is better left as an error vs. an exception isn't so much that it's an expected error condition (in fact, some callers might expect it and others not), but because of the performance characteristics callers generally expect. You don't want disproportionate performance impact to those who need to open potentially non-existent files. If C++ exceptions were as cheap to throw as to avoid, then that would tip the balance significantly.
>std::regex_error and std::format_error are very much of interest to the callers of the APIs that throw them (e.g., because the patterns user-provided and the callers expect potential failures) but that doesn't mean they shouldn't be exceptions
Most commonly, regexes and format string are passed from program data, not user input, so in the majority of cases I don't think it's correct to say that errors are an expected situation. Programmer error is definitely not something that can be handled at the call site, so it makes for a prime candidate to be signaled by an exception.
>Or, for example, the only entity ever really interested in an std::out_of_range exception is the caller (say, catching it around a call like std::accumulate(i, j, [&](const auto& key) { return container.at(key); })).
Why would you write exception handling code around that call instead of ensuring before the call that the indices are valid? If you did ensure that and an exception was still thrown, that's the kind of situation that the caller is not able to resolve, so why would it be interested in the exception? What could it possibly do to recover once it's been proven that the vector was changed concurrently?
>If C++ exceptions were as cheap to throw as to avoid, then that would tip the balance significantly.
No, I don't agree. Sorry for not making my position clearer. What I said previously assumes that you don't have any additional constraints beyond designing the best error handling possible. If you have technical reasons to avoid exceptions (they're too expensive, you're about to cross an FFI boundary, etc.) then that's a reason to stay away from them. I think you should use exceptions up to as much as I said. To use your metaphor, my argument is the floor under the plate of reasons to use exceptions, and the balance can only tip in the other direction.
> Throwing an exception and letting it unwind the stack way up (perhaps even all the way up to main()) is the sensible solution
No. I would never in a million years do this.
If the API is that a function is infallible and then I decide that it’s a fallible function then that’s a pretty major change and I’m just gonna have to update all the call sites to deal with a fallible return result.
Saying throw an exception and bubble up to main provides just about zero value. Might as well just call std::abort. Which is also something I would never do.
> Saying that you prefer Result over exceptions is like saying that you prefer strings to functions. They do different things.
So here’s the thing. In 20+ professional years as a C++ dev I have never ever once worked in a codebase where exceptions were used. Certainly never in first party code. Only when dealing with annoying thirdparty libraries that leveraged them.
I think your comment “contract can’t be fulfilled” is cheating. No. You’ve simply made a new contract and the new contract is that under certain cases an error is returned in the form of an exception.
> Saying throw an exception and bubble up to main provides just about zero value. Might as well just call std::abort. Which is also something I would never do.
I'm sorry but this is where you're clearly wrong. The whole point is unwinding doesn't have to necessarily happen all the way to main(); there is a ton of value in doing this, and it is not at all equivalent to aborting. It lets someone in the call chain do something other than abort, or clean up stuff that they otherwise might not have a chance to. Like logging an error, telling the client there was an internal error, dumping additional information that wouldn't be useful in the successful case, and/or moving on to another task. All gracefully, without any intermediate functions having to care (aside from providing basic exception safety), and without having to throw your hands up and give up. Aborting without being asked is rather presumptuous and robs your callers of all opportunities to do anything about the problem you encountered.
People do this stuff and find it useful... you're effectively telling them all that they're doing something useless and they may as well just abort. That's... quite a claim.
>If the API is that a function is infallible and then I decide that it’s a fallible function then that’s a pretty major change and I’m just gonna have to update all the call sites to deal with a fallible return result.
What if you don't control those call sites?
>Might as well just call std::abort.
Sure. I mean, not really, because the caller cannot handle an abort. You're making a decision for the caller that the situation is unresolvable, where the caller might disagree.
>No. You’ve simply made a new contract and the new contract is that under certain cases an error is returned in the form of an exception.
If the function doesn't use exceptions for normal error conditions, then no, it's not a new contract, because you don't need to do or know anything specific to handle the situation. You could do something like
and not have to worry about the specifics. It's just an exception. You don't have to care about what exactly happened, you just care that something that couldn't be resolved happened. When exceptions are misused you see stuff like
Not always, but this does usually mean that the exception is part of the contract of the function. It's a condition that the caller must handle as part of the normal usage of the function. FileNotFound exceptions are quite often a prime example of exception abuse.
Replying to your other comment here:
>They’re fallible functions. Don’t write fallible APIs that require exceptions to report errors! That’s bad API design!
I disagree. You should ensure your arguments are valid before indexing vectors and dereferencing optionals. You wouldn't iterate a vector like this, I imagine?
for (size_t i = 0;; i++){
auto x = vector.at(i);
if (!x.has_value())
break;
//...
}
If I am choosing to change the API contract then someone who wants to use the new API has to update. This is not a big deal.
> If the function doesn't use exceptions for normal error conditions, then no, it's not a new contract
I disrespectfully and emphatically disagree. I do not accept your definition of contract.
> You could do something like (try-catch wrapper)
Let me be clear. Having to add a bunch of random fucking try-catch bullshit around every fucking function call is EXACTLY why I hate exceptions and is EXACTLY what I think is bad software design.
If you think a function should return a value or some unspecified exception whose details are irrelevant then that function could return an option with no information loss, or a result with an Error that is ignored.
> You wouldn't iterate a vector like this, I imagine?
I wouldn’t use at(i) for iteration. The only reason for a function like at(i) to exist is because you want it to be fallible.
> Let me be clear. Having to add a bunch of random fucking try-catch bullshit around every fucking function call is EXACTLY why I hate exceptions and is EXACTLY what I think is bad software design.
The whole point of exceptions is that you don’t need to handle errors at every call site. You can just have one central try-catch block at a place where you have a way to deal with the error, such as report it to the user.
>If I am choosing to change the API contract then someone who wants to use the new API has to update. This is not a big deal.
Throwing lets you handle the new situation without changing the API at all.
>Let me be clear. Having to add a bunch of random fucking try-catch bullshit around every fucking function call is EXACTLY why I hate exceptions and is EXACTLY what I think is bad software design.
See, that's what happens when you form your opinions on half-digested ideas. Let me be clear. You don't add "a bunch" of try-catch blocks. You don't wrap every call that's capable of failing exceptionally in a try-catch block. That's exactly how you don't use exceptions. The whole point of exceptions is that the compiler will handle the stack unwinding for you so you don't need to worry about it. If you don't want to, or don't know how, or can't handle an exception at a specific point then don't. Let it bubble up for someone else to catch. See the ellipsis in my example? Inside of it you might have a gigantic call tree that performs all sorts of different operations that may all fail in different and unexpected ways. You could write the whole thing and not have a single try-catch besides the one I wrote explicitly. Let me reiterate; this is what you DON'T do:
The only reason you would do something like this is to satisfy a specification such that you have to return different errors, specifically when each of the different calls fails. So... don't specify your functions such that you're required to do this? Just do
foo();
bar();
baz();
or if you really must not throw from the function,
If you add exceptions to a library that didn’t previously use them then I almost definitely have to update my code. The fact that it compiles and runs but will behave in undesirable ways makes it even worse, not better!
> or if you really must not throw from the function,
I’m aware.
But if your library that offers foo adds exceptions now I need to think about it at every single callsite, and probably wrap the function. It’s extremely irritating.
> learn how to use them properly.
In my 20+ years of professional C++ development I have a great experience not using exceptions and a strictly negative experience using them.
Perhaps sometimes I’ll stumble upon a library or codebase where exceptions make the code simpler, easier to understand, and easier to write. But my experience is exceptions make everything strictly worse and that not using exception is a strict win with zero downsides.
>The fact that it compiles and runs but will behave in undesirable ways makes it even worse, not better!
* Exceptions
* Unstable API
* Incorrect behavior
Pick your poison. I know what I prefer.
>But if your library that offers foo adds exceptions now I need to think about it at every single callsite
You really don't. Like I said, it's kind of the whole point of exceptions.
>In my 20+ years of professional C++ development I have a great experience not using exceptions and a strictly negative experience using them.
Hence my recommendation to learn how to use them. I can replace "exceptions" with anything else (computers, diesel engines, HR people), and there's probably someone who holds that belief. That doesn't make it true.
And GTFO with that No True Scotsman nonsense. That a tool can be misused doesn't delegitimize the tool. If you saw someone using classes instead of namespaces you wouldn't conclude classes are bad, you'd call that person a knobhead.
> You really don't. Like I said, it's kind of the whole point of exceptions.
No, this is actually just wrong. With exceptions you “don’t have to think about” the exception getting caught by some higher level catch.
But you do have to think about it in the sense that every single line in your code could unwind. Which makes ensuring you remain in a valid state more difficult.
One of the issues with exceptions isn’t the throw. It’s what do you do after you catch.
> That a tool can be misused doesn't delegitimize the tool.
I’m always open to the possibility that if something I’ve seen has been bad 100 times then on the 101st it might be good. But at some point you really just have to call a spade a spade.
>But you do have to think about it in the sense that every single line in your code could unwind.
No, this is actually just wrong. There is code that can throw, and there is code that cannot possibly throw. The way you write exception-safe code is by not holding manually-managed resources (e.g. raw pointers that own heap allocations, or file descriptors that must be close()d, or anything else that needs cleanup code that has not been put in a destructor) during sections that may throw. In other words, use RAII to manage your resources, regardless of whether exceptions may be thrown.
Program state is significantly more complex than just needing some RAII resources to cleanup via destructors.
> during sections that may throw
Yeah one of the problems with exceptions is it’s impossible to know what “may throw” other than “well I guess literally anything so everything”. It is very irritating.
At the end of the day exceptions are just a little syntactic sugar. Or perhaps syntactic bitters.
It is notable that systems languages designed after C++ all chose to not include exceptions. Go, Zig, Swift, Odin, Jai.
Rust panics are kinda sorta exceptions in that they unwind. But their intended use case is for irrecoverable errors. And of course you can set panic=abort.
C++ exceptions are very rarely treated as so serious module level irrecoverability.
>Program state is significantly more complex than just needing some RAII resources to cleanup via destructors.
You're being rather vague. All throwing does is cause control flow to jump to the nearest catch that can handle the exception, destructing all objects along the way. I struggle to think of an example that could cause problems that isn't some variation of "I had some code after the exception that I needed to run, and it didn't run, because it wasn't set up to run at scope exit". I'd love to see such an example if you have one.
>it’s impossible to know what “may throw”
* If it's a throw statement, it may throw.
* If it's an expression that contains a 'new' operator, it may throw.
* If it's an expression that contains a dynamic_cast to a reference type, it may throw.
* If it calls a function that you don't know that it does not do any of the above, it may throw.
* If it's unknown if a function is called (e.g. types are templated), it may throw.
* Otherwise, it doesn't throw.
If you're managing resources manually, either make sure not to call any functions until you release them, or stop managing them manually. I encourage the latter.
Completely forget about memory allocation and memory allocation like things.
Let’s say I have a physics system that runs an update. Assume we catch outside the update. If anything throws the system is now in an intermediate state and is effectively irrecoverable.
If you want to argue that exceptions should only be used for irrecoverable errors such that the subsystem is not expected to resume then I would list. This is akin to Rust panics which unwind like C++ exceptions but are not intended to resume. I have not read any comments in this large subthread arguing for using exceptions in this narrow style.
> it’s impossible to know what “may throw”
Yeah you’re just saying you should basically assume that any code can throw at any point. I think that’s a really really bad design pattern that makes code significantly harder to reason about. Control flow should be clear and obvious. “Any line of code could immediately unwind to unclear catch” is the objectively not clear and obvious.
But let me turn it around. You tell me an example of a system that doesn’t use exceptions where adding exceptions makes it better.
>Let’s say I have a physics system that runs an update. Assume we catch outside the update. If anything throws the system is now in an intermediate state and is effectively irrecoverable.
That's a transaction kind of scenario. You catch at a recoverable point and rollback to a good state, and if that's not possible, then you simply fail out. I don't understand; what problem did exceptions introduce here? An exception was thrown (i.e. an error happened) during an intermediate operation and the operation as a whole stopped. What would have changed if every function had used error codes instead? It would have been either an error you were incapable of handling (in the sense that you didn't even look at the error code), and the operation would have silently continued in a possibly corrupted state, or it would have been an error you were capable of handling, in which case implement that same handling logic for the exception code.
if (op1() != SUCCESS){
//recover and continue
}
if (op2() != SUCCESS){
//nothing to do so just fail out
return FAIL;
}
//don't care about error so don't even bother checking
(void)op3();
//now the state of the program may be invalid
op4();
becomes
try{
op1();
}catch (/*...*/){
//recover and continue
}
op2(); //let exception be caught by someone who can do something about it
op3(); //same
//sometimes we won't get here, but at least if we do, we know the state of the program is valid
op4();
Is it just that you like ifs more than try-catches?
>If you want to argue that exceptions should only be used for irrecoverable errors such that the subsystem is not expected to resume then I would list.
That would depend on what you mean by "irrecoverable error". I interpret that to mean that the program cannot continue to function safely and it's better to terminate ASAP than to attempt to do anything else at all. If that's what you mean then no, that's not what exceptions are for. Like I said in a sibling comment (https://news.ycombinator.com/item?id=48527216), exceptions are meant to signal an error that may or may not be recoverable that the immediate caller may not know how to handle. Someone in the call stack should be able to decide based on program state how to respond to the error condition; sometimes that will involve rolling back to a valid state, as I said before, perhaps retrying; sometimes you will cancel the operation and discard the interrupted computation; sometimes you will notify the user or log an error; sometimes you will decide that there's actually nothing else for the program to do and clean up and exit.
>You tell me an example of a system that doesn’t use exceptions where adding exceptions makes it better.
Sure, no problem:
if (op1() != SUCCESS)
return FAIL;
if (op2() != SUCCESS)
return FAIL;
if (op3() != SUCCESS)
return FAIL;
//etc.
with exceptions becomes
op1();
op2();
op3();
//etc.
All else being equal, exceptions make this kind of code better by making it more readable. If the non-exception code needs to return both error codes and partial values, it becomes even more noticeable:
auto [result1, error1] = op1();
if (error1 != SUCCESS)
return FAIL;
auto [result2, error2] = op2(result1);
if (error2 != SUCCESS)
return FAIL;
auto [result3, error3] = op3(result2);
> All else being equal, exceptions make this kind of code better by making it more readable.
I just fundamentally disagree that hidden secret control flow makes code more readable. Well, it may be more readable but it is, imho, significantly less understandable.
There’s a reason that literally no modern systems language has adopted C++ exceptions.
We’re just about at the point of discussing syntactic sugar. So one question is “given current C++ capabilities should you use exceptions or not?”. Another is “should C++ add different sugar for error handling?”. And a third is “should a different language adopt exceptions-like design?”.
Imho a zig or rust like error system with a ? operator to return is vastly superior. Fallibility and control flow is super explicit, obvious, and easy to read.
Current C++ is a little jankier. Designs vary. All have tradeoffs. But imho they are all preferable to secret hidden control flow. So exceptions are, in my lived experience, a strictly inferior choice.
>I just fundamentally disagree that hidden secret control flow makes code more readable. Well, it may be more readable but it is, imho, significantly less understandable.
That's cool. I disagree that the principal control path should be made more difficult to read in favor of having really explicit error handling that doesn't actually do anything. That said, I do like Rust's question mark operator; it's a pretty cool middle ground between exceptions and error codes.
So, about that example of exceptions introducing faulty behavior unrelated to resource management that I asked for?
> example of exceptions introducing faulty behavior unrelated to resource management that I asked for?
Well there’s a reason that constructors aren’t allowed to throw. Because it would leave objects in a weird hybrid state.
My physics system example would be the canonical one. You have a system that is transforming from one state to the next. An exception is thrown in the middle of the state transition. Whatever invariants you had for either state is (plausibly) not held. I believe your solution to this was to treat it as a transaction and rewind/restore to the previous state if an error is encountered.
It’s difficult because I would simply literally never use exceptions for anything ever. My experience with them is strictly negative with zero positives of any kind. I genuinely can not think of a single thing they make better. Nor have I ever encountered a library or codebase where I felt exceptions made it better. But boy howdy have I been frustrated by exceptions.
boost often has two APIs one with exceptions and one with error code reference arguments. I intend to always use the EC version. And god damn is it fucking frustrating when I accidentally use the exception version and so I get a runtime exception for a vanilla error that I wasn’t expecting. Which is why hidden control flow is evil!
>It’s difficult because I would simply literally never use exceptions for anything ever. My experience with them is strictly negative with zero positives of any kind.
So what I'm getting is that you don't have enough experience with exceptions to judge whether a bug related to exceptions is caused by the code not being exception-safe, thus leaking resources after a throw; by exceptions being thrown for non-exceptional error conditions, thus necessitating excessive try-catching; or by plain old incorrect error handling, thus resulting in trashed program state. So when you encounter a bug like this, instead of figuring out what the actual problem is, you just hack away until there are no more exceptions in sight, and then you actually start to work on fixing the logic. Well, if you're comfortable remaining ignorant and pretending that a language feature doesn't exist, then have at it, I guess.
>boost often has two APIs one with exceptions and one with error code reference arguments. I intend to always use the EC version.
I don't like the throwing versions, either, and consider them examples of how not to use exceptions. I'd have to think carefully of a counterexample, but in general I'd say it's a bad idea to throw across library boundaries.
> If you add exceptions to a library that didn’t previously use them then I almost definitely have to update my code.
No, that's the whole point. You let them bubble up to the top of the event loop and you report the error to the user. As a user, anything else leads to shitty software where the programmer tries to outsmart the world around them (and fails, obviously, leading to worse end-user experience than just admitting that you don't and can't have control over everything)
What user? I work on systems where there might not be a keyboard or a mouse or a display and where the use of there is one doesn’t care that the “flooblutz was out of turving.” The only thing stack unwinding gets me is it forces me to restart my program from the beginning.
> One of the problems with exceptions is it’s utterly impossible to know if a given function call can return exceptions and if so what they are.
Could you please explain how exactly you know if a function might abort?
And how you figure out exactly which error codes a function might return if it does return an error?
And why/how your techniques for figuring out the above don't work for exceptions?
> Python is the bloody worst because I never effing know what the hell any damn function can throw or return. It’s so so frustrating.
No, it's pretty possible. Virtually any interesting function you call can throw AttributeError or TypeError, if nothing else, simply by virtue of you passing an object of the wrong type or behavior.
"But I don't mean those particular exceptions! I don't care about them." Well yeah that's kind of the point. If you can pretend that problems you don't know how to handle don't exist, then you can pretend the same for exceptions and errors. You're not supposed to care about the entire universe of possible error conditions; it's not only impossible but also you wouldn't be able to handle all of them anyway. You handle everything you can reasonably handle and then let the rest propagate, not the other way around. Same for error codes and exceptions.
"But the documentation would tell me which error codes I care about!" Well it can do that for exceptions too. If the documentation sucks then bring it up with the API developer not the language developer.
> But I’ll take Rust results over exceptions 10,000% of the time. Not even a question.
Sure, feel free to do that. Or use error codes in C++, whatever you prefer. Not like I'm trying to turn this into a Rust vs. C++ debate.
Functions aborting is not something I’ve ever really had to think about. Exception heavy codebases it’s something I have to ALWAYS think about.
Error codes are pretty bad. Global error code is awful. An error enum is pretty nice.
So here’s the thing. I’ve been a professional C++ programmer for 20 years. Not once have I ever worked in a codebase that used exceptions. It’s fine. Occasionally I use a thirdparty library that does use exceptions and it’s bloody awful.
> Functions aborting is not something I’ve ever really had to think about.
There are certainly a lot of programs for which it matters a whole lot. In a lot of applications you absolutely don't want your program to crash. I'm not even talking about rocket launching or pacemakers or HFT here... I just mean something as simple as a web server or job server. It's the difference between taking down the server (say, getting DoS'd) vs. not.
> So here’s the thing. I’ve been a professional C++ programmer for 20 years. Not once have I ever worked in a codebase that used exceptions. It’s fine.
I work on codebases without exceptions too; it's not just you. "It's fine" in the same sense that working with a messy desk or floor "is fine". One certainly can live with it -- especially when there's no better option available -- but the clutter gets in the way, distracts you, and sometimes leaves you with a little papercut.
> Occasionally I use a thirdparty library that does use exceptions and it’s bloody awful.
You're not wrong -- this can certainly happen -- but I think you've misidentified the problems. There are other reasons for this than what you've listed in [1] or that I have the energy to fully expand on here, but the biggest one is probably the fact that you're getting the worst of both worlds by the mere virtue of mixing them. Nobody claimed that mixing code that uses exceptions with code that assumes they're disabled would lead to a good outcome. It neither lets you simplify the problem by assuming exceptions will work like they're supposed to, nor does it let you simplify the problem by assuming exceptions are nonexistent. It's like putting cars and bicycles on the same sections of the road all over the town. It's going to lead to more crashes than if you had just stuck with one or the other, and that's not because cars or bikes inherently suck.
Why can't you? They don't want to provide info for a credit check, you want human accountability. All that requires is for them to use a debit card for whatever service (prepaid or postpaid). Law enforcement can trace that if needed. No need for credit checks or really any other information directly in the hands of the telco.
It doesn't make sense to include the capex cost to train a model in this kind of discussion, because that cost is fixed.
Consider a model that costs $100m to train.
If the vendor then prices it such that each inference token has a margin of 10% over the variable costs to serve (power + server costs), whether or not they cover their costs is based entirely on how many tokens they can sell.
If they sell less than $1bn of tokens, they lose money - the break even point is 10x100m = $1bn.
If they sell $10bn of tokens they make a ton of money.
This also means you can't credibly calculate how much of the fixed training expense is covered by your token spend, because until the model is retired and you can account for how much inference it ran you don't know what percentage of the training cost each sold token was responsible for.
Cost is fixed if you train a model once in several years, if you have to train 3/4 times per year to stay competitive training cost is a thing.
You have to include also failed training sessions and experiments in the math.
There are no official figures but given how fast new models are rolled out, I wouldn't be surprised if neither Anthropic nor OAI manage to cover the full models cost.
I think the capex being fixed assumes you can just stop training the next model. But its not clear that you can afford to do that and keep selling tokens.
And if capabilities plateau such that training the next one is useless, then the margins will drop fast due to competition.
Just guessing, but I assume because it’s arguably off-topic as defined by the HN guidelines. I don’t think it should be flagged, though.
“Off-Topic: Most stories about politics, or crime, or sports, or celebrities, unless they're evidence of some interesting new phenomenon. If they'd cover it on TV news, it's probably off-topic.”
This being evidence of an interesting new phenomenon is literally the entire premise of the blog post though. And it sure as hell didn't look like it was covered on the main news headlines; I know I only heard about it because of HN. The author is pretty clearly claiming this is a new phenomenon literally in the title itself!
It's new, but is it "interesting?" Does it "satisfy intellectual curiosity?"
Many people here will consider this categorically off topic and flag accordingly because politics doesn't satisfy theirs. Even if it's a good article, and even if the discussion is on-topic and civil.
What is "intellectual curiosity" that doesn't include curiosity about whether, when, and how often the world superpower commits a war crime? For reference just the other day we had [1] on the front page. Was knowing the consumer price index for the month really all that much more satisfying of "intellectual curiosity" than this?
> data center companies could genuinely at least open up for tours to try to appeal to the public, if public approval is apparently such a concern.
Do you actually find anything appealing about a datacenter? I've been to one and while it was mildly cool from the standpoint of "wow how do they manage this many machines" I didn't find anything appealing about it that would make me want it in my neighborhood.
You just press backspace and hit the accent mark key or for a printing press stack the accent mark on top of the letter. People ditched accents because they were rarely used in English writing (only really being used for some loanwords), not because simplifications were forced by typewriters or the printing press (which handle non-English languages just fine).
For printing presses we're talking about the influence of the first printing presses hundreds of years before industrialization which were imported from Germany and even when they started making their own in England they were more like clones and used imported designs and parts. The early machines had a heavy influence on the written language particularly at times when under 1 in 10 people could write, and with the advent of movable type the people who learned to write were heavily influenced by what they read... books printed on German-design machines. You really only need one generation in a situation like that to dramatically change the language. Losing þ, æ, and ð
"Ye Olde Mill" or whatever archaic silliness you'll find at fairs and whatnot was the result of the printing press dropping þ (as in þe, þ is just th-) and was never supposed to be pronounced with a "y" sound.
"Ye Olde" ye was not the same word as "Hear ye, hear ye!", that ye is a plural 'you' basically the same word as "y'all" and never had a thorn.
This happened with more than one letter. For instance the Scots language had a letter yogh (https://en.wikipedia.org/wiki/Yogh), which was written somewhat like a rounded "3" but lower on the line. Early printers had only the characters of the English language, and since this character looked like a hand-written z, that is what they used in its place. Hence the name "Menzies" is pronounced "Ming-is", since that isn't actually a z.
Welsh suffered more: it used to be full of "k"s. When the first Welsh Bible was printed, the English printer did not have enough "k"s, and substituted "c", and the language now does not use "k" at all. Apparently the printer's note on the matter still exists.
"ye" in "ye Olde mill" is actually just "the" but originally "þe"/"þee". The first printing presses to England were imported from Germany, which never used þ, so printers used something that looked sorta similar, thus "y".
"Ye" was a different word, the 2nd person non-formal version of "you" (which was historically formal: see-Shakespeare and how he played with "ye" and "you"). Thorn was on its way out along with "ð" both of which were in Middle English. The sounds didn't leave English, but we merged it into one letter cluster "th" (think "that" and "the", which have different th sounds).
The pronunciation is so bad though. The consonants are mostly fine, but the way we write vowels is a total mess. We'd need at least a dozen vowel letters to sanely represent English. And we could cut a couple consonant letters to help make room, for maybe 30 letters total, still no accents.
Just today the NYT Strands puzzle gave a great example: you can find one set of prefixes that make each of the following rhyme, and a different set of prefixes that make them all sound different:
-ooze -oose -ews -ues -use -oes -uise
You can do this purely with prefixes ending in consonants, i.e. not by turning -use into -ouse, for example.
(spoilers for the little -ooze puzzle: for rhymes, booze choose brews blues ruse shoes cruise; for non-rhymes, snooze loose pews plagues obtuse toes guise; many others are possible, and rhyming or lack thereof may depend on accent).
It’s great compression: Y sometimes a vowel, sometimes a consonant.
And while not encoded on a keyboard, it still blows my mind that English has a crazy number of past tenses - and a such a bad hack of a future tense that it’s hard to classify as such.
reply