News for hackers. Stuff that matters.
Re:T* makes for a poor optional<T&> by kentonv on Monday December 13, 2021 @02:13PM (#29543173)
Note the original title is: T* makes for a poor optional<T&>

The last `<T&>` there is key, but seems to have been removed from the HN version of the title.

This blog post is not arguing for the use of optionals in general (it assumes everyone already agrees with that). It is instead making a much more wonky argument that std::optional<T> should support T being a reference type, which apparently is not supported right now.

For most purposes, it seems std::optional<T&> would behave very similarly T*, but the ergonomics would be better in certain template scenarios. It seems like a valid argument to me, but definitely getting into the weeds a bit.

Aside: IMO std::optional in general is disappointing because it doesn't actually solve the worst problem with nullable pointers: dereferencing a null std::optional is still undefined behavior. I wish the standard had gone with a design that forces the developer to write an explicit check when unwrapping the optional...

Re:T* makes for a poor optional&lt;T&&gt; by nwallin on Monday December 13, 2021 @04:00PM (#29544588)
> Aside: IMO std::optional in general is disappointing because it doesn't actually solve the worst problem with nullable pointers: dereferencing a null std::optional is still undefined behavior. I wish the standard had gone with a design that forces the developer to write an explicit check when unwrapping the optional...

You can use `.value()` to deref an optional instead of `operator*` or `operator->`. It will throw an exception on empties.

IMHO the primary purpose for a function returning a `std::optional` instead of either returning a value on success or throwing an exception on failure is that you can use it in codebases where exceptions are disabled for whatever reason. If the behaviors of `.value()` vs `operator*` were swapped, such that `operator*` throws exceptions and `.value()` is undefined behavior, all the people who wanted it for the purposes of eschewing exceptions, the crowd who wanted `std::optional` the most, would be getting the verbose code.

Re:T* makes for a poor optional&lt;T&&gt; by masklinn on Monday December 13, 2021 @04:54PM (#29545170)
> You can use `.value()`

Which is bad at every level if resolution: it’s more verbose to do “the right thing” (obviously), it’s more expensive to do “the right thing” (because if you’ve properly checked you’re paying the check twice and praying the compiler can remove the redundant check), and it’s incompatible with other pointers to do “the right thing” (because pointers use ! And *).

So .value() it mostly worthless, if it’s being used it’s an assertion with overhead which can take down your program.

> all the people who wanted it for the purposes of eschewing exceptions, the crowd who wanted `std::optional` the most, would be getting the verbose code.

And nothing of value would be lost (except for it not behaving as a “standard pointer” anymore).

Re:T* makes for a poor optional&lt;T&&gt; by kllrnohj on Monday December 13, 2021 @05:48PM (#29545704)
> it’s more expensive to do “the right thing” (because if you’ve properly checked you’re paying the check twice and praying the compiler can remove the redundant check)

Eh that's hardly a solid complaint here. Since these are header-defined templates, it's all inlined. And any compiler will absolutely remove those redundant checks as a result. And an unchecked .value() would still be available if you really did object to that "overhead", so it doesn't violate any C++ principals here.

I do kinda think that operator-> & operator* as a result did the assertion, and value() bypassed it. But this would also be the opposite behavior of other std:: classes, like std::vector (operator[] being unchecked vs. at() being checked).

Re:T* makes for a poor optional&lt;T&&gt; by germandiago on Monday December 13, 2021 @06:37PM (#29546206)
I do not think it is. What does the language do on * dereferencing? Yes, it does not do a check. So if you do it now you have to remember two different rules, one rooted deep inside C and C++ minimal overhead philosophy. Now multiply by the number of types (unique_ptr, shared_ptr, optional and probably more) and remember the correct rule.

I do not think there is something bad with it. It does the same for the same syntax and you have a `.value()` checked access anyway.

Re:T* makes for a poor optional&lt;T&&gt; by junon on Monday December 13, 2021 @06:04PM (#29545887)
> praying the compiler can remove the redundant check

It can in pretty much every single case even on -O1.

Re:T* makes for a poor optional&lt;T&&gt; by kitkat_new on Monday December 13, 2021 @06:34PM (#29546188)
I somehow have my doubts if that check was made in entirely different parts of the program
Re:T* makes for a poor optional&lt;T&&gt; by junon on Monday December 13, 2021 @09:35PM (#29547523)
What do you mean?
Re:T* makes for a poor optional&lt;T&&gt; by kentonv on Monday December 13, 2021 @05:28PM (#29545515)
Throwing an exception is somewhat better but still not what I really want, usually. I want the compiler to make me write an if()-like statement checking if the value is non-null before I can dereference it.
Re:T* makes for a poor optional&lt;T&&gt; by Pxtl on Monday December 13, 2021 @07:00PM (#29546393)
Try/catch is if-like if you do it right.... But it's also not mandatory. Hence the argument for Java's checked exceptions... which didn't pan out in the end.
Re:T* makes for a poor optional&lt;T&&gt; by kentonv on Monday December 13, 2021 @09:42PM (#29547563)
Throwing exceptions in C++ is also incredibly slow, you generally don't want to do it in any path that you expect will actually be exercised in normal operation.

Checked exceptions were a nice idea in theory that definitely didn't work well at all in practice. IMO exceptions should be reserved for "panic" situations, as a friendlier alternative to crashing. (But I also feel they should be used liberally in such situations...)

Re:T* makes for a poor optional&lt;T&&gt; by Pxtl on Monday December 13, 2021 @09:47PM (#29547607)
I cut my teeth on Python's "forgiveness not permission" model and find that exceptions are usually the cleanest model since so few languages have pleasant syntax for alternate return-types, and returning a status code and using out parameters for the actual result is miserable.
Re:T* makes for a poor optional&lt;T&&gt; by masklinn on Tuesday December 14, 2021 @12:28AM (#29548556)
Sure but python was built on a model of signalling anything via exceptions, C++ was not, and it sacrifices the exceptional case for the benefit of the nom-exceptional one.
Re:T* makes for a poor optional&lt;T&&gt; by hoseja on Tuesday December 14, 2021 @08:26AM (#29551226)
Using exceptions for control flow etc. etc.
Re:T* makes for a poor optional&lt;T&&gt; by ameliaquining on Monday December 13, 2021 @10:23PM (#29547816)
Disabling exceptions means that you can't catch them, not that you can't throw them.* If an exception would be thrown under such circumstances, the process aborts. This would have been a safer default than undefined behavior (though inconsistent with other fundamental and standard C++ APIs, which generally prefer for the obvious default to be fast rather than safe).

* This is technically wrong, because, e.g., destructors don't run on the way out; I'm going for pithiness here rather than strict accuracy.

Re:T* makes for a poor optional&lt;T&&gt; by colejohnson66 on Monday December 13, 2021 @06:07PM (#29545924)
> Note the original title is: T* makes for a poor optional<T&>

> The last `<T&>` there is key, but seems to have been removed from the HN version of the title.

HN seems to like stripping out HTML-tag-like blocks instead of escaping them. Why though?

Re:T* makes for a poor optional&lt;T&&gt; by strager on Monday December 13, 2021 @03:46PM (#29544423)
> I wish the standard had gone with a design that forces the developer to write an explicit check when unwrapping the optional...

If this is how std::optional worked, hardly anyone would use it.

Re:T* makes for a poor optional&lt;T&&gt; by kentonv on Monday December 13, 2021 @05:23PM (#29545452)
> If this is how std::optional worked, hardly anyone would use it.

OK... Well, this is how kj::Maybe works and having written several hundred thousand lines of code using it, I think it works well.

https://github.com/capnproto/capnproto/blob/master/kjdoc/tou...

Re:T* makes for a poor optional&lt;T&&gt; by kllrnohj on Monday December 13, 2021 @05:44PM (#29545665)
Well, that seems to be using macros to cover up the syntax, which of course the C++ committee isn't going to recommend or use for anything new (nor should they).

The actual implementation of Maybe doesn't seem to force anything, it just returns a pointer to the stored value. There's no enforcement of any kind that anything is checked as a result. There's some hoop-jumping with friend classes to "hide" the readMaybe() function to make the non-macro usage as ugly as possible to strongly encourage using the macro-convention, but that's hardly "enforcement".

It's a cute syntax & macro pattern, but it's hardly a good fit for a C++ standard, either.

Re:T* makes for a poor optional&lt;T&&gt; by kentonv on Monday December 13, 2021 @09:38PM (#29547541)
The C++ committee could come up with actual syntax for this so it doesn't need macros.

> There's no enforcement of any kind that anything is checked as a result. There's some hoop-jumping with friend classes to "hide" the readMaybe() function to make the non-macro usage as ugly as possible to strongly encourage using the macro-convention, but that's hardly "enforcement".

Sure fine. Anyone who wants to reach into the internal APIs could also just as easily do `#define private public` and bypass every protection C++ has. We're not trying to defend against malicious developers here.

Re:T* makes for a poor optional&lt;T&&gt; by brandmeyer on Monday December 13, 2021 @05:47PM (#29545694)
To be fair, languages which require explicit unwrapping also provide syntactic short-hands for the most common idioms. Long-handed if/else (or pattern matching) is used to implement the short-hands or as a last resort.

See also value_or and the C++20 monadic methods on std::optional.

http://open-std.org/JTC1/SC22/WG21/docs/papers/2021/p0798r6....

Re:T* makes for a poor optional&lt;T&&gt; by kamray23 on Monday December 13, 2021 @05:58PM (#29545807)
that is how it works everywhere else and that is how it is used everywhere else
Re:T* makes for a poor optional&lt;T&&gt; by jcelerier on Monday December 13, 2021 @08:02PM (#29546872)
how is that an argument ? If I was fine with how any other language does things (and $deity knows I've tried a lot) I would not be using c++
Re:T* makes for a poor optional&lt;T&&gt; by winter_squirrel on Monday December 13, 2021 @04:13PM (#29544718)
Why, other languages that require unwrapping it still see plenty of people using optional. In fact, I would have more inclination to use it in my projects if that was the only way to do it.