Should we use optional<bool>? Alternatives?

209 views
Skip to first unread message

David Roger

unread,
May 31, 2021, 12:41:58 PM5/31/21
to Chromium-dev
Is there any recommendation for or against optional<bool>, for example:

  absl::optional<bool> is_enabled;

where is_enabled == nullopt means that we don't know if it's enabled (e.g. because we're not initialized yet).

Problem: this may be error prone, as someone may be tempted to write code like this to check if the service is enabled:

  if (is_enabled) {
     // Do something requiring the service to be enabled.
  }

The code above is a bug, because the condition actually checks if |is_enabled| has a value, and not if the inner value of the optional is true.

Even in the absence of bugs, the code is harder to read, because at a glance, when seeing code like "if (is_enabled)" out of context, it easy to assume that |is_enabled| is a bool instead of an optional and misunderstand the code.

See also external discussions: example, example

Alternatives:
- Use an enum with three values (kFalse, kTrue, kUnknown). There are a few precedents in chrome code. Pro: simple. Con: verbose.
- Use a class like boost::tribool which has a safer and more explicit way to convert to bool (safe_bool()). Pro: nice behavior. Con: complex, need to learn an extra class.

Questions:
Is there already something like tribool in Chrome that we should use, or any plan to add it?
Any recommended option: keep using optional<bool>, or go with the enum?

I think my preference would be for the enum over optional<bool>, unless something like tribool already exists in chrome code.

Alexei Svitkine

unread,
May 31, 2021, 1:20:07 PM5/31/21
to David Roger, Nico Weber, Chromium-dev
This seems similar to:


Where clang now has a warning against a similar scenario that can happen with bool*. Perhaps something similar should be done for abs::optional? (Although not sure where - in our custom clang analyzer? since presumably clang core doesn't know anything about absl types.).

+Nico Weber who might have thoughts.

--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev
---
You received this message because you are subscribed to the Google Groups "Chromium-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-dev...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-dev/CAL3rL5h_Wme%2Bx4%2B5Y7vQNr2TA854TL5JUwbe9BqMVaQxvAqX3Q%40mail.gmail.com.

Daniel Cheng

unread,
May 31, 2021, 6:19:25 PM5/31/21
to Alexei Svitkine, George Burgess, David Roger, Nico Weber, Chromium-dev
I believe that clang CL was abandoned due to hitting too many false positives.

This is probably a check that could make sense for clang-tidy rather than the clang plugin that Chrome builds with, due to the risk of false positives. I don't know if we have any pre-existing mechanism for extending clang-tidy with our own checks. +George Burgess 

I would strongly encourage using an enum for this. It's 100% clear, despite being a little verbose, and as a bonus, it even uses less storage (one byte for the enum vs two bytes for the optional<bool>). I suppose it's something we could consider adding to //base if it's that common.

Daniel

dan...@chromium.org

unread,
Jun 1, 2021, 9:39:45 AM6/1/21
to Daniel Cheng, Alexei Svitkine, George Burgess, David Roger, Nico Weber, Chromium-dev
On Mon, May 31, 2021 at 6:18 PM Daniel Cheng <dch...@chromium.org> wrote:
I believe that clang CL was abandoned due to hitting too many false positives.

This is probably a check that could make sense for clang-tidy rather than the clang plugin that Chrome builds with, due to the risk of false positives. I don't know if we have any pre-existing mechanism for extending clang-tidy with our own checks. +George Burgess 

I would strongly encourage using an enum for this. It's 100% clear, despite being a little verbose, and as a bonus, it even uses less storage (one byte for the enum vs two bytes for the optional<bool>). I suppose it's something we could consider adding to //base if it's that common.

+1 I would use an enum over 2 levels of bools.
 

Jeremy Roman

unread,
Jun 1, 2021, 10:42:02 AM6/1/21
to danakj chromium, Daniel Cheng, Alexei Svitkine, George Burgess, David Roger, Nico Weber, Chromium-dev
+1 to using an enum. Also please avoid calling the enumerators kTrue and kFalse if at all possible. kEnabled/kDisabled is clearer IMHO and often even more clear terms are possible.

Nohemi Fernandez

unread,
Jun 1, 2021, 11:46:59 AM6/1/21
to dro...@chromium.org, Chromium-dev
Another alternative may be using OptionalOrNullptr, which is a simple wrapper around absl::optional that would resolve the confusion that may result with absl::optional<bool> and has some, albeit limited, precedence in the Chrome codebase. 

Peter Boström

unread,
Jun 1, 2021, 12:34:52 PM6/1/21
to fern...@google.com, dro...@chromium.org, Chromium-dev
To me, I don't see that OptionalOrNullptr helps. The existence of the optional<bool> will always have the operator bool foot-shooter, even if you use other ways of accessing the optional in original checked-in code. if(optional) or return optional; has to be caught in code review right now. This isn't a possible bug to accidentally introduce with a tri-state enum.

Imo when using an optional<bool> you have a pretty strong reason to always use optional.has_value() as you have to express what you actually mean, but that's right now only enforceable through code review, as would OptionalOrNullptr. "No optional<bool>" is easier to enforce or audit.

Peter Boström

unread,
Jun 1, 2021, 12:39:48 PM6/1/21
to fern...@google.com, dro...@chromium.org, Chromium-dev
FWIW I would be happy if optional<bool>::operator bool was a compiler warning/error in src/, but I have no idea if that's remotely feasible. That would also fix the foot shooter instead of requiring different types when what you want to express is an optional<bool>. You also wouldn't reinvent the API for kEnabled,kDisabled,kUndefined every time with different enum values in every location (unless there's a base::OptionalBool).

Reilly Grant

unread,
Jun 1, 2021, 2:25:37 PM6/1/21
to pb...@chromium.org, fern...@google.com, dro...@chromium.org, Chromium-dev
In general I like the existence of  optional<T>::operator bool but maybe we can make an exception for optional<bool> that doesn't allow it to nudge this gun away from developers' feet.
Reilly Grant | Software Engineer | rei...@chromium.org | Google Chrome


dan...@chromium.org

unread,
Jun 1, 2021, 2:47:07 PM6/1/21
to Reilly Grant, Peter Boström, fern...@google.com, David Roger, Chromium-dev
On Tue, Jun 1, 2021 at 2:25 PM Reilly Grant <rei...@chromium.org> wrote:
In general I like the existence of  optional<T>::operator bool but maybe we can make an exception for optional<bool> that doesn't allow it to nudge this gun away from developers' feet.

Removing it just for optional<bool> will be a bit of a headache in templated code. The template works until you pass in the wrong type, now someone has to go fix the template.

I'd rather we drop the operator bool from absl entirely if we want to do that, but it would preclude us from ever migrating to std::optional (if our hardening checks don't already in practice end up doing so).

dan...@chromium.org

unread,
Jun 1, 2021, 2:48:27 PM6/1/21
to Reilly Grant, Peter Boström, fern...@google.com, David Roger, Chromium-dev
On Tue, Jun 1, 2021 at 2:45 PM <dan...@chromium.org> wrote:
On Tue, Jun 1, 2021 at 2:25 PM Reilly Grant <rei...@chromium.org> wrote:
In general I like the existence of  optional<T>::operator bool but maybe we can make an exception for optional<bool> that doesn't allow it to nudge this gun away from developers' feet.

Removing it just for optional<bool> will be a bit of a headache in templated code. The template works until you pass in the wrong type, now someone has to go fix the template.

I'd rather we drop the operator bool from absl entirely if we want to do that, but it would preclude us from ever migrating to std::optional (if our hardening checks don't already in practice end up doing so).

(to be clear, I don't consider that to have to be a deal breaker myself)

Colin Blundell

unread,
Jun 2, 2021, 3:11:54 AM6/2/21
to Dana Jansens, Reilly Grant, Peter Boström, Nohemi Fernandez, David Roger, Chromium-dev
Could we just make it a Chromium C++ style guide directive to use an enum instead of optional<bool> and have a presubmit check that disallows optional<bool> from being used in the codebase?

Peter Kasting

unread,
Jun 2, 2021, 5:09:53 AM6/2/21
to Colin Blundell, Dana Jansens, Reilly Grant, Peter Boström, Nohemi Fernandez, David Roger, Chromium-dev
I don't think this proposed rule "pulls its weight", so to speak. I also wonder what is different about Chromium here that means we should have such a rule when the Google store guide does not 

PK

Sylvain Defresne

unread,
Jun 2, 2021, 5:13:32 AM6/2/21
to Colin Blundell, Dana Jansens, Reilly Grant, Peter Boström, David Roger, Chromium-dev
base::Value uses absl::optional<T> for the new API to get items for key/path in a dictionary (except for string where it returns a pointer to the internal stored string).

This means that base::Value::FindBoolKey() returns a base::optional<bool>. For the user, this is nice, since the code to base::Value new dictionary API is the same for all types. Using an enum here would make the bool type different (also, not sure that we could use anything besides kTrue, kFalse, kUnset for base::Value since there is not enough context for the API to know what the bool mean).

For less generic code, I agree that an enum is probably a better option.
-- Sylvain

Colin Blundell

unread,
Jun 2, 2021, 5:14:34 AM6/2/21
to Peter Kasting, Colin Blundell, Dana Jansens, Reilly Grant, Peter Boström, Nohemi Fernandez, David Roger, Chromium-dev
On Wed, Jun 2, 2021 at 11:08 AM Peter Kasting <pkas...@chromium.org> wrote:
I don't think this proposed rule "pulls its weight", so to speak. I also wonder what is different about Chromium here that means we should have such a rule when the Google store guide does not

I would definitely defer to your judgment. I thought specifically of the suggestion as an alternative to that of generically removing optional<T>::operator bool. The latter to me seems like a net loss.

Colin Blundell

unread,
Jun 2, 2021, 5:17:40 AM6/2/21
to Sylvain Defresne, Colin Blundell, Dana Jansens, Reilly Grant, Peter Boström, David Roger, Chromium-dev
On Wed, Jun 2, 2021 at 11:12 AM Sylvain Defresne <sdef...@chromium.org> wrote:
base::Value uses absl::optional<T> for the new API to get items for key/path in a dictionary (except for string where it returns a pointer to the internal stored string).

This means that base::Value::FindBoolKey() returns a base::optional<bool>. For the user, this is nice, since the code to base::Value new dictionary API is the same for all types. Using an enum here would make the bool type different (also, not sure that we could use anything besides kTrue, kFalse, kUnset for base::Value since there is not enough context for the API to know what the bool mean).

That's good to know, thanks!

David Roger

unread,
Jun 2, 2021, 6:01:38 AM6/2/21
to Colin Blundell, Nohemi Fernandez, Sylvain Defresne, Dana Jansens, Reilly Grant, Peter Boström, David Roger, Chromium-dev
Thank you all for the feedback, this is a very interesting discussion.

I've heard some other good points off-thread (thanks +Nohemi Fernandez):

- "is_enabled" is probably a bad name for an optional, and it would be better to use "maybe_is_enabled" or "try_is_enabled".
Similarly a function returning an optional should probably be called "MaybeIsEnabled()" or "TryIsEnabled()".
Having consistent naming conventions for optionals could probably help here reducing confusion.

- google style and internal google code do not ban optional<bool>

Also note there are some related recommendations for google internal code:
  go/totw/141#optional-values-and-scoped-assignments (internal link).
  They acknowledge it is a dangerous pattern, and propose mitigations (always use has_value() rather than automatic conversion, limit the scope of the variable as much as possible)

Xiaohan Wang (王消寒)

unread,
Feb 28, 2022, 10:21:23 PM2/28/22
to dro...@chromium.org, Colin Blundell, Nohemi Fernandez, Sylvain Defresne, Dana Jansens, Reilly Grant, Peter Boström, Chromium-dev
Just hit this in one of my own CLs. Given this is a common (dangerous) pattern, I'd suggest we have a dedicated class/struct wrapper for this, e.g. 

```
class OptionalBool {
  bool is_true() { return data_.value(); }
  bool is_set() { return data_.has_value(); }\
  // no bool() operator!
 private:
  absl::optional<bool> data_;
};
```

Thoughts and comments?

Xiaohan

Daniel Cheng

unread,
Feb 28, 2022, 10:36:34 PM2/28/22
to xhw...@chromium.org, dro...@chromium.org, Colin Blundell, Nohemi Fernandez, Sylvain Defresne, Dana Jansens, Reilly Grant, Peter Boström, Chromium-dev
I can imagine situations where we'd still have an absl::optional<bool>. Instead of doing this, I think it'd be nice to add a clang-tidy check instead (I think this could even be upstream?) that would warn when not using the more explicit has_value().

Daniel

Xiaohan Wang (王消寒)

unread,
Mar 1, 2022, 2:34:53 PM3/1/22
to Thomas Sepez, Daniel Cheng, dro...@chromium.org, Colin Blundell, Nohemi Fernandez, Sylvain Defresne, Dana Jansens, Reilly Grant, Peter Boström, Chromium-dev
I'd like to have a common solution in Chromium instead of having every developer defining their own solutions. It could be a wrapper class or enum or something else. Personally I like a wrapper class more since we can have a very clean interface...

On Tue, Mar 1, 2022 at 10:59 AM Thomas Sepez <tse...@google.com> wrote:
Alternatively one might avoid the bool in the first place with something more descriptive like

enum class Foo { kNotEnabled = 0, kEnabled };
optional<Foo> is_enabled;

esp. if we are passing this value as an argument somewhere, Foo::kNotEnabled avoids writing /*is_enabled=*/false, and such.


Daniel Cheng

unread,
Mar 1, 2022, 2:41:42 PM3/1/22
to Xiaohan Wang (王消寒), Thomas Sepez, dro...@chromium.org, Colin Blundell, Nohemi Fernandez, Sylvain Defresne, Dana Jansens, Reilly Grant, Peter Boström, Chromium-dev
There's a cost to this too though--more special-case patterns that every developer will need to remember. That's why I'd prefer we just stick with optional<bool> and just add warnings when someone uses the explicit bool conversion or * instead of the clearer has_value() and value().

(bool* has a similar issue too...)

Daniel
Reply all
Reply to author
Forward
0 new messages