markable -- informal review request
Hi Everyone, I would like to ask your opinion, suggestions, and perhaps an
informal review of the 'markable' library. An alternative to
boost::optional when performance really matters. It is the second
incarnation of the 'compact_optional' library that I have presented last
year.
The main differences from the previous version:
* name change: it is called 'markable' so that it is not confused with
'optional'. It uses "mark values" and mark policies"
* it has the ability to mark an empty state even for the types with strong
invariants, by marking a bit pattern rather than any proper value of T (an
idea by Matt Calabrese)
An example use case:
typedef markable
On 16 September 2016 at 15:23, Andrzej Krzemienski
Hi Everyone, I would like to ask your opinion, suggestions, and perhaps an informal review of the 'markable' library. An alternative to boost::optional when performance really matters. It is the second incarnation of the 'compact_optional' library that I have presented last year.
The main differences from the previous version: * name change: it is called 'markable' so that it is not confused with 'optional'. It uses "mark values" and mark policies" * it has the ability to mark an empty state even for the types with strong invariants, by marking a bit pattern rather than any proper value of T (an idea by Matt Calabrese)
An example use case:
typedef markable
> opt_int; opt_int oi; opt_int o2 (2); assert (!oi.has_value());assert (o2.has_value());assert (o2.value() == 2); static_assert (sizeof(opt_int) == sizeof(int), "");
The github repository: https://github.com/akrzemi1/markable And documentation therein: https://github.com/akrzemi1/markable/tree/master/documentation
Any comments, suggestions or critique are most welcome.
Regards, &rzej;
I am interested in doing a quick review of this library, but I have first to ask why "markable"? I'm not sure I understand the intended meaning of this word in this context. Joël Lamotte
2016-09-20 11:12 GMT+02:00 Klaim - Joël Lamotte
On 16 September 2016 at 15:23, Andrzej Krzemienski
wrote: Hi Everyone, I would like to ask your opinion, suggestions, and perhaps an informal review of the 'markable' library. An alternative to boost::optional when performance really matters. It is the second incarnation of the 'compact_optional' library that I have presented last year.
The main differences from the previous version: * name change: it is called 'markable' so that it is not confused with 'optional'. It uses "mark values" and mark policies" * it has the ability to mark an empty state even for the types with strong invariants, by marking a bit pattern rather than any proper value of T (an idea by Matt Calabrese)
An example use case:
typedef markable
> opt_int; opt_int oi; opt_int o2 (2); assert (!oi.has_value());assert (o2.has_value());assert (o2.value() == 2); static_assert (sizeof(opt_int) == sizeof(int), "");
The github repository: https://github.com/akrzemi1/markable And documentation therein: https://github.com/akrzemi1/markable/tree/master/documentation
Any comments, suggestions or critique are most welcome.
Regards, &rzej;
I am interested in doing a quick review of this library, but I have first to ask why "markable"? I'm not sure I understand the intended meaning of this word in this context.
Joël Lamotte
Hi Joël, Thank you for expressing your interest. You bring up a good point. The docs lack rationale for the naming. I will try to update them soon.
The reason is somewhat psychological or "social"; and at the bottom boils down to the fact that the compromise around std::optional in The Standards Committee is very fragile, and decisions around `markable` may affect it. Clearly, there is some overlap between `optional` (boost::optional, std::optional) and `markable`. I was explicitly requested to remove any 'optional' from this library's name, in order not to make any suggestion that I am competing with `optional` or that I am offering a superior alternative -- I am not. You can look at my library from two perspectives: 1. I am giving you a more efficient alternative to optional<int>, at the cost of compromising the interface. 2. It is just an `int` with some magical value, say -1, but I am making it more explicit that this `-1` marks a special case. In this second sense, "mark", "markable", "marked" quite naturally reflect the fact that I am marking one value as special, which is the core idea behind this library. One could consider other alternatives like "magic_val", but they are not much better, and do not transform into adjectives and verbs that easily ("magic_valued"?). Does that sound convincing? Regards, &rzej;
On 20 Sep 2016 12:04 pm, "Andrzej Krzemienski"
[...].
One could consider other alternatives like "magic_val", but they are not much better, and do not transform into adjectives and verbs that easily ("magic_valued"?).
Does that sound convincing?
Maybe. More seriously, yes please submit it to boost, I have seen reinvented (a few by myself) this too many times. A few comments: * Consider, maybe, a different name (OK, OK I'll stop). * The first template parameter should be the stored T itself, pass the policy as a separate optional parameter. * Pick a sensible default policy. I like nan for floats, otherwise value initialisation is a good default. For integers is easy to have a policy specifying the value inline. * to avoid the bag of functions issue with policies, consider using ADL for customisation and use the stateless policy just to drive the lookup. * The policy itself can be used for tagging, no need for an extra parameter. * Markable should be trivially copyable, assignable and destructible when the underlying T is, at least when not using the pod storage policy. This might be already the case. * Add flatMap? That's all for now, -- gpd
On 21 Sep 2016 12:32 am, "Giovanni Piero Deretta"
On 20 Sep 2016 12:04 pm, "Andrzej Krzemienski"
wrote: [...].
One could consider other alternatives like "magic_val", but they are not much better, and do not transform into adjectives and verbs that easily ("magic_valued"?).
Does that sound convincing?
Maybe.
More seriously, yes please submit it to boost, I have seen reinvented (a
few by myself) this too many times. A few comments:
* Consider, maybe, a different name (OK, OK I'll stop). * The first template parameter should be the stored T itself, pass the
* Pick a sensible default policy. I like nan for floats, otherwise value initialisation is a good default. For integers is easy to have a policy specifying the value inline. * to avoid the bag of functions issue with policies, consider using ADL for customisation and use the stateless policy just to drive the lookup. * The policy itself can be used for tagging, no need for an extra
* Markable should be trivially copyable, assignable and destructible when
policy as a separate optional parameter. parameter. the underlying T is, at least when not using the pod storage policy. This might be already the case.
* Add flatMap?
That's all for now,
Oh, I forgot: from the docs:
"It is impossible to alter the "contained value" through the access to
function value[...]
With the assignment being prevented, we could get the following surprising
behaviour:
marked
2016-09-21 1:32 GMT+02:00 Giovanni Piero Deretta
On 20 Sep 2016 12:04 pm, "Andrzej Krzemienski"
wrote: * Add flatMap?
Thanks for the feedback. I am just reading through it. Just one immediate question. What do you mean by "Add flatMap" here? What would it do? Regards, &rzej;
On 21 Sep 2016 7:21 am, "Andrzej Krzemienski"
2016-09-21 1:32 GMT+02:00 Giovanni Piero Deretta
: On 20 Sep 2016 12:04 pm, "Andrzej Krzemienski"
wrote:
* Add flatMap?
Thanks for the feedback. I am just reading through it. Just one immediate question. What do you mean by "Add flatMap" here? What would it do?
Apply a function f to the contained element of the markable<T> (if non empty). If f is from T->U returns markable<U>, if it is T->markable<U> simply returns that. Exactly like std::future::then. In fact it should probably be called 'then' instead of flatMap. Optional should also have it of course. -- gpd
On 16 Sep 2016 at 15:23, Andrzej Krzemienski wrote:
An example use case:
typedef markable
> opt_int; opt_int oi; opt_int o2 (2); assert (!oi.has_value());assert (o2.has_value());assert (o2.value() == 2); static_assert (sizeof(opt_int) == sizeof(int), "");
I'm not sure about the value add of this simplified optional
implementation. What compelling use cases does it have over optional?
In my own boost::outcome::option<T>, it's just one of many
specialisations of basic_monad
2016-09-21 18:35 GMT+02:00 Niall Douglas
On 16 Sep 2016 at 15:23, Andrzej Krzemienski wrote:
An example use case:
typedef markable
> opt_int; opt_int oi; opt_int o2 (2); assert (!oi.has_value());assert (o2.has_value());assert (o2.value() == 2); static_assert (sizeof(opt_int) == sizeof(int), "");
I'm not sure about the value add of this simplified optional implementation. What compelling use cases does it have over optional?
Compared to optional:
1. no spacial overhead for storing "initialized" flag:
sizeof(markable
specialisations of basic_monad
and has all the advantages of being a basic_monad, including implicit convertibility to more expressive basic_monad's, monadic operators etc. It also has the same ridiculous optimisability that basic_monad has and typically reduces down to no runtime overhead (which from inspection so does your markable). Yours does have likely very low impact on compile times though. Mine does stress the optimiser in release builds a lot.
Compared to boost::outcome::option? I do not know boost::outcome::option that well? Are its characteristics documented anywhere? Thank you for response, &rzej
participants (4)
-
Andrzej Krzemienski
-
Giovanni Piero Deretta
-
Klaim - Joël Lamotte
-
Niall Douglas