5 ms·
> The idea is that optionals allow you to pass optional data by value. Yes, and kj::Maybe was doing the same before std::optional was standardized. It's disap
by kentonv 6y ago
> The idea is that optionals allow you to pass optional data by value.
Yes, and kj::Maybe was doing the same before std::optional was standardized.
It's disappointing that the committee chose only to solve this problem while not also solving the problem of forgetting to check for null -- often called "the billion-dollar mistake".
> Dereferencing null optionals is UB for consistency with dereferencing pointers. All uses of operator* should have the same semantics
My argument is that `std::optional` should not have an operator* at all. `kj::Maybe` does not have operator* nor `operator->`.
> If you want to dereference an optional that may be null, use the .value_or() method. For the times when you absolutely know the optional has a value use operator*.
This is putting a lot of cognitive load on the developer. They must remember which of their variables are optionals, in order to remember whether they need to check for nullness. The fact that they use the same syntax to dereference makes it very easy to get wrong. This is especilaly true in modern IDEs where developers may be relying on auto-complete. If I don't remember the type of `foo`, I'm likely to write `foo->` and look at the list of auto-complete options, then choose one, without ever realizing that `foo` is an optional that needs to be checked for null.
In KJ, you MUST write:
KJ_IF_MAYBE(value, maybeValue) {
use(value);
} else {
handleNull();
}
Or if you're really sure the maybe is non-null, you can write:
use(KJ_ASSERT_NONNULL(maybeValue));
This does a runtime check and throws an exception if the value is null. But more importantly, it makes it really clear to both the writer and the reader that as assumption is being made.
- CyberRabbi 6y ago> My argument is that `std::optional` should not have an operator* at all. `kj::Maybe` does not have operator* nor `operator->`. That’s fair. >> If you want to dereference an optional that may be null, use the .value_or() method. For the times when you absolutely know the optional has a value use operator > This is putting a lot of cognitive load on the developer. They must remember which of their variables are optionals, Not really. Teams with programmers that are bad at keeping track of the state of their variables can simply have a policy to always use .value_or()/.value() C++ doesn’t impose this on its users because it generally assumes its users are responsible enough to make their own policy. > The fact that they use the same syntax to dereference makes it very easy to get wrong. I disagree, the operator* has the same semantics as pointers did, making it no more semantically hazardous. There exists other methods on optional that have the behavior you want.
- kentonv 6y ago> always use .value_or()/.value() But neither of these solve the problem either. Neither one forces the programmer to really confront the possibility of nullness and write the appropriate if/else block. Throwing an exception rather than crashing is only a slight improvement IMO. > I disagree, the operator* has the same semantics as pointers did, making it no more semantically hazardous. It was already severely hazardous with pointers, that's the problem.
- CyberRabbi 6y ago>> always use .value_or()/.value() > But neither of these solve the problem either. Neither one forces the programmer to really confront the possibility of nullness and write the appropriate if/else block. .value_or() actually does and you can certainly add a lint check against dereferencing optional or using .value() if you’d like. C++ does not Yet provide Case-style syntax for handling variants like rust, outside of macros and the standard library will certainly not define macros. I think what you have done for your codebase makes sense based on your preferences but I think the standard optional works pretty well given the variety of code based and styles it’s intended to support. > It was already severely hazardous with pointers, that's the problem. So then don’t use the dereference operator.
- kentonv 6y agokj::Maybe has an `orDefault()` method that is like `.value_or()` but I find that it is almost never useful. You almost always want to execute different logic in the null case, rather than treat it as some default value.
- CyberRabbi 6y agoThen you can make a quick helper subroutine that adds a monadic interface to optional and you can lint away all non-conforming uses of optional.
- pierrebai 6y ago
- jcelerier 6y ago> It's disappointing that the committee chose only to solve this problem while not also solving the problem of forgetting to check for null -- often called "the billion-dollar mistake". it's likely ~30 loc to wrap std::optional in your own type that checks for null. if std::optional checked for null and these `if` branch showed up as taking the couple nanoseconds that make you go past your time budget in your real-time system (especially if people were doing things like if(b) { foo(b); bar(b); baz(*b); }) then you have to reimplement the whole of it instead. Don't forget that you can still use C++ on 8mhz microcontrollers.
- monocasa 6y agoThe ideal situation is then to not use std::optional for those cases rather than to make std::optional next to useless for it's stated case. If it gets in the way of your goal on an 8Mhz controller, take the optionality check out of your tight loop and convert to a null pointer safely where it doesn't matter. Deeply embedded is already used to picking and choosing features, or explicitly running with the bumper rails off in the subset of cases where it matters. We like the normal primitives not being neutered for us because we still use a lot of them outside of our tight loops.
- CyberRabbi 6y ago> than to make std::optional next to useless for it's stated case. This is such a ridiculous and obviously false assertion that it’s indistinguishable from satire. Optional is widely used and was modeled from a pre-existing boost class which was itself widely used. Do you actually write C++ professionally?
- monocasa 6y agoYes. And I think (hope?) that std::optional is going to make it's way into the dust bins of history like auto_ptr. When the answer is "just don't deference it if it's null", then why not just use a pointer in the first place?
- 6y ago