It's why I think it competes for market share with some of what is currently Java/C# and similar languages. A lot of people who use those languages care about correctness, and Rust is big step up in this regard.
It's why I think it competes for market share with some of what is currently Java/C# and similar languages. A lot of people who use those languages care about correctness, and Rust is big step up in this regard.
In some cases, that's not a problem or it's even the best thing to do. However, you end up writing this way all the time in an exception-based language, which is where the problem arises.
Non-exception based languages tend to throw the problems in your face and make them something you can't ignore. Which is not fun. But it is often what you need.
For example, say you have a pandas dataframe with a column "foo" and you accidentally try to read column "fooo". Instead of getting a useful exception like "PandasException: Attempted to read nonexistent column 'fooo'", you get a traceback 10 layers deep, terminating in something like "pandas.hashtable.PyObjectHashTable.get_item" which ought to be totally invisible to you, the library user.
Edit: by "this" I meant to agree with parent: Getting a useful, well defined exception is how it should be done. Psycopg2 does this very well.
I'm not sure that's such a bad thing. Exception handling doesn't mean you should be handling all exceptions, just that you can recover if one does occur. If an exception is 100% relevant to what you're doing then yes absolutely handle it, or even clean up your own state before propagating the exception if you can't. But please don't catch any and all exception to suppress or obfuscate them by wrapping it in another domain specific exception.
You can't because you don't know where it came from so you don't know what happened, why, or if it was recoverable. You can take a stab at it, but that's it.
Maybe that's a particular language constraint? In general exceptions have a stack trace and it's evident where an exception came from.
At least in my experience exceptions don't have to be handled unless or until they're disruptive. If you have a scheduler or task processor code that needs to run continuously then you're going to have robust exception handling, but not necessarily comprehensive or appropriate. For other areas of code however the exception handling isn't necessarily requisite.
Result/Maybe types are awesome, because you just don't get unexpected runtime exceptions due to programming error. You only get them when a genuine problem occurs.
That's a valid concern. I've seen attempts to document the custom exception types that classes can throw but it's never discoverable. It's compounded by the fact that uncaught exceptions bubble up.
I don't know that most people would sift through all the possible exceptions and write selective catch blocks to handle them. I think in general they will either catch all exceptions or none, if or until they need to handle a specific scenario that presents itself in production.
My perspective though is primarily of LOB Apps or Integrations and not widely consumed public code or apps.
Overall Python has really good stack traces, but the hyper-dynamic nature of so many common libraries does make it tough to grok sometimes.
I usually end up reaching for the PyCharm debugger which is fantastic anyway.
Maybes explicitly express what the programmer has foreseen, exceptions form a safety net over it. You need both in a wholesome language. That's wht even Haskell has exceptions.
That's a lot of possible error to handle! I don't like exception's invisible flow but I think that they are good for 'should never happen' errors.
But from my understanding, this is not directly related to the borrow checker, which tracks who owns a reference and is allowed to modify it or not.
(That being said if you had a "default" case earlier, the compiler won't complain)
(I don't remember the specific underlying feature flag name, sorry).
EDIT: It's called `-Wswitch`
> Warn whenever a switch statement has an index of enumerated type and lacks a case for one or more of the named codes of that enumeration. (The presence of a default label prevents this warning.) case labels outside the enumeration range also provoke warnings when this option is used (even if there is a default label). This warning is enabled by -Wall.
The real problems with C enums aren't about matching completion, they are that:
- There is no guarantee that a variable value is in the enum range;
- A C (or Java, or C#) enum is a very poor type and can not represent all the data that a Rust enum carries. Developers usually use them with union types to solve that problem, but then there aren't any warnings for most problems anymore.
In Rust, enums are a core data structure with completely equal status to structs, and are used pervasively throughout the language including the standard library.
Notably, both Option (which is used instead of null) and Result (which is used for error handling) are enums, which means that you thse correctness checks for every null and every error condition, on by default. Thats a huge deal as these are often the source of unexpected runtime errors.
This is just basic type safety stuff.
Edit: typo
C++ had boost.variant which did exhaustiveness checking since ... 2002 (and an std version since C++17).