Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > What's your experience with optional values?

Reply
Thread Tools

What's your experience with optional values?

 
 
DeMarcus
Guest
Posts: n/a
 
      12-26-2010
Hi,

In databases you provide NULL if the value is missing. When using
objects on the free store in C++ you can use NULL to represent a missing
value. When using non-pointer values you may not.

I know several ways to solve this, but what I'm looking for is a
/uniform/ way to deal with missing values both for non-pointer values
and free store values.

When dealing with non-pointer values I can do the following.
boost:ptional<int> getMyInt();

When dealing with free store values I can do the following.
std::unique_ptr<int> getMyInt();

However, I would like to have something uniform for my whole
application. Something like.
my:pt<int> getMyInt();
my:pt<int*> getMyInt();
my:pt<std::unique_ptr<int>> getMyInt();

where my:pt works like boost:ptional for non-pointer values and as a
transparent container if a pointer (to avoid the unnecessary check for
the object since we already can check if the pointer is NULL).

With some hard work I could probably come up with some template
solution, but my question is:

* Does this look intuitive to you? Would this uniformity add to the
understanding and consistency of the code?


I could also just use std::unique_ptr everywhere I need optional values,
but with big structures of data it would be a performance hit to
allocate memory for each non-pointer member.

The simplest solution would be to just go for boost:ptional when using
non-pointer types and std::unique_ptr for pointer types, but I thought
it could be a value having a uniform name. Do you agree with me?


Thanks,
Daniel


 
Reply With Quote
 
 
 
 
Öö Tiib
Guest
Posts: n/a
 
      12-27-2010
On Dec 26, 10:17*pm, DeMarcus <(E-Mail Removed)> wrote:
> Hi,
>
> In databases you provide NULL if the value is missing. When using
> objects on the free store in C++ you can use NULL to represent a missing
> value. When using non-pointer values you may not.
>
> I know several ways to solve this, but what I'm looking for is a
> /uniform/ way to deal with missing values both for non-pointer values
> and free store values.


What sort of uniformity you want? There is difference when something
is empty, unknown, failed/invalid (as fallible) or missing (as
optional).

> When dealing with non-pointer values I can do the following.
> boost:ptional<int> getMyInt();


It is member function declaration? It may result with get-and-get-
getted idiom:

int intFromT = t.getMyInt().get();

> When dealing with free store values I can do the following.
> std::unique_ptr<int> getMyInt();
>
> However, I would like to have something uniform for my whole
> application. Something like.
> my:pt<int> getMyInt();
> my:pt<int*> getMyInt();
> my:pt<std::unique_ptr<int>> getMyInt();


> where my:pt works like boost:ptional for non-pointer values and as a
> transparent container if a pointer (to avoid the unnecessary check for
> the object since we already can check if the pointer is NULL).
>
> With some hard work I could probably come up with some template
> solution, but my question is:
>
> * Does this look intuitive to you? Would this uniformity add to the
> understanding and consistency of the code?


This feels over-engineered. Lot of classes have invalid or exceptional
states anyway in them and it is more likely that they do right thing
in context. So there is a danger that by making them all uniform you
lose valuable context information (is it empty, unknown, not
available, failed, invalid or missing).

> I could also just use std::unique_ptr everywhere I need optional values,
> but with big structures of data it would be a performance hit to
> allocate memory for each non-pointer member.
>
> The simplest solution would be to just go for boost:ptional when using
> non-pointer types and std::unique_ptr for pointer types, but I thought
> it could be a value having a uniform name. Do you agree with me?


When i want uniform semantics for different types then i write a
family of function overloads. Something like bool IsMissing( T
const& ) that expresses such state.

 
Reply With Quote
 
 
 
 
DeMarcus
Guest
Posts: n/a
 
      12-27-2010
On 12/27/2010 02:47 AM, Öö Tiib wrote:
> On Dec 26, 10:17 pm, DeMarcus<(E-Mail Removed)> wrote:
>> Hi,
>>
>> In databases you provide NULL if the value is missing. When using
>> objects on the free store in C++ you can use NULL to represent a missing
>> value. When using non-pointer values you may not.
>>
>> I know several ways to solve this, but what I'm looking for is a
>> /uniform/ way to deal with missing values both for non-pointer values
>> and free store values.

>
> What sort of uniformity you want? There is difference when something
> is empty, unknown, failed/invalid (as fallible) or missing (as
> optional).
>


A very good point actually if one wants to be truly consistent. When
looking at the Motivation for boost:ptional they mention that failing
values should probably be signaled as an exception.

http://www.boost.org/doc/libs/1_45_0...nal.motivation

You mention several other situations. I see them as this (please give
your comments if you don't agree).

* Empty - That's a valid value, like an empty string. Dangerous for all
entries where an empty string doesn't have a clear meaning. If it does
not, it should be caught and signaled with an exception.

* Failed, invalid - Should be signaled with an exception.

* Unknown, missing - Should be signaled in a special way, like NULL for
pointers and some other way for non-pointers.

Now, since you spotted exactly the things that goes around in my head,
my question is; do you see it would be important to be able to
distinguish between Unknown and Missing, and maybe even be able to say
that a value is Empty? Or can we group them together; Unknown, Missing,
Uninitialized, Not available, Not applicable, Empty, all represented
with NULL?


>> When dealing with non-pointer values I can do the following.
>> boost:ptional<int> getMyInt();

>
> It is member function declaration? It may result with get-and-get-
> getted idiom:
>
> int intFromT = t.getMyInt().get();
>


Yes, it has to be that way.

>> When dealing with free store values I can do the following.
>> std::unique_ptr<int> getMyInt();
>>
>> However, I would like to have something uniform for my whole
>> application. Something like.
>> my:pt<int> getMyInt();
>> my:pt<int*> getMyInt();
>> my:pt<std::unique_ptr<int>> getMyInt();

>
>> where my:pt works like boost:ptional for non-pointer values and as a
>> transparent container if a pointer (to avoid the unnecessary check for
>> the object since we already can check if the pointer is NULL).
>>
>> With some hard work I could probably come up with some template
>> solution, but my question is:
>>
>> * Does this look intuitive to you? Would this uniformity add to the
>> understanding and consistency of the code?

>
> This feels over-engineered. Lot of classes have invalid or exceptional
> states anyway in them and it is more likely that they do right thing
> in context. So there is a danger that by making them all uniform you
> lose valuable context information (is it empty, unknown, not
> available, failed, invalid or missing).
>


You have a point, but I don't know how to proceed. I find it useful to
be able to say that an integer is uninitialized or unset. To me, that
would be represented with NULL. But if you say that it would be valuable
to be able to distinguish between e.g. Not available and unknown, then I
need to rethink the design.

>> I could also just use std::unique_ptr everywhere I need optional values,
>> but with big structures of data it would be a performance hit to
>> allocate memory for each non-pointer member.
>>
>> The simplest solution would be to just go for boost:ptional when using
>> non-pointer types and std::unique_ptr for pointer types, but I thought
>> it could be a value having a uniform name. Do you agree with me?

>
> When i want uniform semantics for different types then i write a
> family of function overloads. Something like bool IsMissing( T
> const& ) that expresses such state.
>


But where do you store that information? Let's say you have a struct
like this.

struct MyData
{
std::string name;
std::string address;
int age;
double height;
int weight;
};

How would you distinguish missing, invalid, empty, etc. values in this
struct? And how would would you implement the signaling of those?


Thanks,
Daniel
 
Reply With Quote
 
Öö Tiib
Guest
Posts: n/a
 
      12-28-2010
On Dec 27, 1:04*pm, DeMarcus <(E-Mail Removed)> wrote:
> On 12/27/2010 02:47 AM, Tiib wrote:
>
> > On Dec 26, 10:17 pm, DeMarcus<(E-Mail Removed)> *wrote:
> >> Hi,

>
> >> In databases you provide NULL if the value is missing. When using
> >> objects on the free store in C++ you can use NULL to represent a missing
> >> value. When using non-pointer values you may not.

>
> >> I know several ways to solve this, but what I'm looking for is a
> >> /uniform/ way to deal with missing values both for non-pointer values
> >> and free store values.

>
> > What sort of uniformity you want? There is difference when something
> > is empty, unknown, failed/invalid (as fallible) or missing (as
> > optional).

>
> A very good point actually if one wants to be truly consistent. When
> looking at the Motivation for boost:ptional they mention that failing
> values should probably be signaled as an exception.
>
> http://www.boost.org/doc/libs/1_45_0...html/index.htm...


Depends on nature of failure. Exception is active and expensive way to
give up in hope that someone up there will resolve it. For example:
Requested was a "strategy for doing something"; such was not found or
proven was that it is impossible; responder may throw or may return a
"strategy of doing nothing". On lot of cases requester has nothing to
do anyway (and if it has then it can always reconsider on response to
do nothing) so why to throw it?

> You mention several other situations. I see them as this (please give
> your comments if you don't agree).
>
> * Empty - That's a valid value, like an empty string. Dangerous for all
> entries where an empty string doesn't have a clear meaning. If it does
> not, it should be caught and signaled with an exception.
>
> * Failed, invalid - Should be signaled with an exception.
>
> * Unknown, missing - Should be signaled in a special way, like NULL for
> pointers and some other way for non-pointers.
>
> Now, since you spotted exactly the things that goes around in my head,
> my question is; do you see it would be important to be able to
> distinguish between Unknown and Missing, and maybe even be able to say
> that a value is Empty? Or can we group them together; Unknown, Missing,
> Uninitialized, Not available, Not applicable, Empty, all represented
> with NULL?


If distinguishing makes sense or not depends on problem domain and
objects nature. Missing bag is very different from empty bag.
Additionally there is saturated "null object" pattern that is real
object that does nothing on any request. Very useful sometimes. Andy
gave a good example else thread ... floating point NaN. You add
substract, or multiply it as lot you want, it is still a NaN.

[...]

> > When i want uniform semantics for different types then i write a
> > family of function overloads. Something like bool IsMissing( T
> > const& *) that expresses such state.

>
> But where do you store that information? Let's say you have a struct
> like this.
>
> struct MyData
> {
> * * std::string name;
> * * std::string address;
> * * int age;
> * * double height;
> * * int weight;
>
> };
>
> How would you distinguish missing, invalid, empty, etc. values in this
> struct? And how would would you implement the signaling of those?


You think too much about data. You even name it as "Data". For me
behavior of object is way more important aspect than data. So for any
other object in system designed by me it is an interface exposed to
them and not a pile of data. Interface may be abstract and references
to all missing MyDatas in system may point at single immutable
MissingMyData that behaves in all situations like missing one should.
When it is so on case of MyData then it can be distinguished by memory
address:

bool IsMissing( MyData const& data )
{
return (&data == &MissingMyData);
}

<Nitpick> "age of something" is usually considered as time-span
between "start of it" and "now" so if "now" ever advances then "age"
should also increase. </Nitpick>
 
Reply With Quote
 
DeMarcus
Guest
Posts: n/a
 
      12-28-2010
On 12/27/2010 12:25 PM, Andy Champ wrote:
> On 27/12/2010 11:04, DeMarcus wrote:
> <snip>
>>
>> Now, since you spotted exactly the things that goes around in my head,
>> my question is; do you see it would be important to be able to
>> distinguish between Unknown and Missing, and maybe even be able to say
>> that a value is Empty? Or can we group them together; Unknown, Missing,
>> Uninitialized, Not available, Not applicable, Empty, all represented
>> with NULL?
>>

> </snip>
>
> Can I draw a comparison with floating point? There are lots of NaN
> values (Not A Number) - and it can be important to distinguish them.
>
> Andy


That's a good point! How do you handle NaN? In my opinion these things
are important to have a uniform way to handle in your framework.
Otherwise all programmers in your company come up with their own
solutions for their particular task, reinventing the wheel every time.


 
Reply With Quote
 
Öö Tiib
Guest
Posts: n/a
 
      12-28-2010
On Dec 28, 10:18*am, DeMarcus <(E-Mail Removed)> wrote:
> On 12/27/2010 12:25 PM, Andy Champ wrote:
>
>
>
>
>
> > On 27/12/2010 11:04, DeMarcus wrote:
> > <snip>

>
> >> Now, since you spotted exactly the things that goes around in my head,
> >> my question is; do you see it would be important to be able to
> >> distinguish between Unknown and Missing, and maybe even be able to say
> >> that a value is Empty? Or can we group them together; Unknown, Missing,
> >> Uninitialized, Not available, Not applicable, Empty, all represented
> >> with NULL?

>
> > </snip>

>
> > Can I draw a comparison with floating point? There are lots of NaN
> > values (Not A Number) - and it can be important to distinguish them.

>
> > Andy

>
> That's a good point! How do you handle NaN? In my opinion these things
> are important to have a uniform way to handle in your framework.
> Otherwise all programmers in your company come up with their own
> solutions for their particular task, reinventing the wheel every time.


For example your responsibility is to record results of some sort of
measurements 100 times per second, every 10 milliseconds. When your
sensors fail you record NaN. You don't break your work with exception,
because *you* are fine. It is responsibility of others to analyze the
records. When such failures happen only once per second then there are
still 99 fine data-points per second and your measurements can be
considered very reliable. When your sensors are broken or gone off-
line the there are row of NaNs and then analyzers raise alarms. You
still continue recording until explicitly told to stop. If you did
instead filter out the noise then you had to record also the time
together with each measurement and that would double up the
requirement for data storage.
 
Reply With Quote
 
DeMarcus
Guest
Posts: n/a
 
      12-28-2010
On 12/28/2010 10:17 AM, Öö Tiib wrote:
> On Dec 28, 10:18 am, DeMarcus<(E-Mail Removed)> wrote:
>> On 12/27/2010 12:25 PM, Andy Champ wrote:
>>
>>
>>
>>
>>
>>> On 27/12/2010 11:04, DeMarcus wrote:
>>> <snip>

>>
>>>> Now, since you spotted exactly the things that goes around in my head,
>>>> my question is; do you see it would be important to be able to
>>>> distinguish between Unknown and Missing, and maybe even be able to say
>>>> that a value is Empty? Or can we group them together; Unknown, Missing,
>>>> Uninitialized, Not available, Not applicable, Empty, all represented
>>>> with NULL?

>>
>>> </snip>

>>
>>> Can I draw a comparison with floating point? There are lots of NaN
>>> values (Not A Number) - and it can be important to distinguish them.

>>
>>> Andy

>>
>> That's a good point! How do you handle NaN? In my opinion these things
>> are important to have a uniform way to handle in your framework.
>> Otherwise all programmers in your company come up with their own
>> solutions for their particular task, reinventing the wheel every time.

>
> For example your responsibility is to record results of some sort of
> measurements 100 times per second, every 10 milliseconds. When your
> sensors fail you record NaN. You don't break your work with exception,
> because *you* are fine. It is responsibility of others to analyze the
> records. When such failures happen only once per second then there are
> still 99 fine data-points per second and your measurements can be
> considered very reliable. When your sensors are broken or gone off-
> line the there are row of NaNs and then analyzers raise alarms. You
> still continue recording until explicitly told to stop. If you did
> instead filter out the noise then you had to record also the time
> together with each measurement and that would double up the
> requirement for data storage.


I think we speak the same language. My point is not to decide what's a
NaN, an Empty entry or Missing Value, and which should raise an
exception or not.

What I'm striving to solve is how to store that second level
information. We can't store Nan in a double saying that -999.9 is NaN,
and we can't say that -1 in an int is a missing value.

So my question remains; is there a nice and uniform way of storing this?
We could use a std:air for everything with pair.first giving the
signal (NaN, Missing, etc.) and pair.second giving the value.

I could probably come up with something, but I was just wondering if the
community had had similar experience and how it's been solved in
different contexts.


 
Reply With Quote
 
DeMarcus
Guest
Posts: n/a
 
      12-28-2010
On 12/28/2010 01:30 AM, Öö Tiib wrote:
> On Dec 27, 1:04 pm, DeMarcus<(E-Mail Removed)> wrote:
>> On 12/27/2010 02:47 AM, Tiib wrote:
>>
>>> On Dec 26, 10:17 pm, DeMarcus<(E-Mail Removed)> wrote:
>>>> Hi,

>>
>>>> In databases you provide NULL if the value is missing. When using
>>>> objects on the free store in C++ you can use NULL to represent a missing
>>>> value. When using non-pointer values you may not.

>>
>>>> I know several ways to solve this, but what I'm looking for is a
>>>> /uniform/ way to deal with missing values both for non-pointer values
>>>> and free store values.

>>
>>> What sort of uniformity you want? There is difference when something
>>> is empty, unknown, failed/invalid (as fallible) or missing (as
>>> optional).

>>
>> A very good point actually if one wants to be truly consistent. When
>> looking at the Motivation for boost:ptional they mention that failing
>> values should probably be signaled as an exception.
>>
>> http://www.boost.org/doc/libs/1_45_0...html/index.htm...

>
> Depends on nature of failure. Exception is active and expensive way to
> give up in hope that someone up there will resolve it. For example:
> Requested was a "strategy for doing something"; such was not found or
> proven was that it is impossible; responder may throw or may return a
> "strategy of doing nothing". On lot of cases requester has nothing to
> do anyway (and if it has then it can always reconsider on response to
> do nothing) so why to throw it?
>


You're right. The programmer has to decide whether a throw is appropriate.

>> You mention several other situations. I see them as this (please give
>> your comments if you don't agree).
>>
>> * Empty - That's a valid value, like an empty string. Dangerous for all
>> entries where an empty string doesn't have a clear meaning. If it does
>> not, it should be caught and signaled with an exception.
>>
>> * Failed, invalid - Should be signaled with an exception.
>>
>> * Unknown, missing - Should be signaled in a special way, like NULL for
>> pointers and some other way for non-pointers.
>>
>> Now, since you spotted exactly the things that goes around in my head,
>> my question is; do you see it would be important to be able to
>> distinguish between Unknown and Missing, and maybe even be able to say
>> that a value is Empty? Or can we group them together; Unknown, Missing,
>> Uninitialized, Not available, Not applicable, Empty, all represented
>> with NULL?

>
> If distinguishing makes sense or not depends on problem domain and
> objects nature. Missing bag is very different from empty bag.
> Additionally there is saturated "null object" pattern that is real
> object that does nothing on any request. Very useful sometimes. Andy
> gave a good example else thread ... floating point NaN. You add
> substract, or multiply it as lot you want, it is still a NaN.
>
> [...]
>
>>> When i want uniform semantics for different types then i write a
>>> family of function overloads. Something like bool IsMissing( T
>>> const& ) that expresses such state.

>>
>> But where do you store that information? Let's say you have a struct
>> like this.
>>
>> struct MyData
>> {
>> std::string name;
>> std::string address;
>> int age;
>> double height;
>> int weight;
>>
>> };
>>
>> How would you distinguish missing, invalid, empty, etc. values in this
>> struct? And how would would you implement the signaling of those?

>
> You think too much about data. You even name it as "Data". For me
> behavior of object is way more important aspect than data. So for any
> other object in system designed by me it is an interface exposed to
> them and not a pile of data. Interface may be abstract and references
> to all missing MyDatas in system may point at single immutable
> MissingMyData that behaves in all situations like missing one should.
> When it is so on case of MyData then it can be distinguished by memory
> address:
>
> bool IsMissing( MyData const& data )
> {
> return (&data ==&MissingMyData);
> }
>


Hm, interesting. Do you define MissingMyData as a global constant?
Anyway, still, with this solution you force all MyData to be pointers,
right?

 
Reply With Quote
 
Bart van Ingen Schenau
Guest
Posts: n/a
 
      12-28-2010
On Dec 28, 1:15*pm, DeMarcus <(E-Mail Removed)> wrote:
>
> I think we speak the same language. My point is not to decide what's a
> NaN, an Empty entry or Missing Value, and which should raise an
> exception or not.
>
> What I'm striving to solve is how to store that second level
> information. We can't store Nan in a double saying that -999.9 is NaN,
> and we can't say that -1 in an int is a missing value.
>
> So my question remains; is there a nice and uniform way of storing this?
> We could use a std:air for everything with pair.first giving the
> signal (NaN, Missing, etc.) and pair.second giving the value.
>
> I could probably come up with something, but I was just wondering if the
> community had had similar experience and how it's been solved in
> different contexts.


My experience is that there are no "one size fits all" solutions in
programming. All attempts at such a solution eventually end up being a
"one size fits none".

There are essentially two ways of reporting an absent/empty/whatever
value: in-band or out-of-band. And which method works best depends on
the types involved and the possible values that can occur within the
application.
In-band signalling (null pointers, NaN, special value outside the
possible range) is often the easiest to work with. But sometimes there
are no spare values that could be used for such a purpose, so you have
to resort to out-of-band signalling, like boost::Optional.

Bart v Ingen Schenau
 
Reply With Quote
 
Pavel Lepin
Guest
Posts: n/a
 
      12-28-2010

Bart van Ingen Schenau wrote:
> There are essentially two ways of reporting an absent/empty/whatever
> value: in-band or out-of-band. And which method works best depends on
> the types involved and the possible values that can occur within the
> application.
> In-band signalling (null pointers, NaN, special value outside the
> possible range) is often the easiest to work with. But sometimes there
> are no spare values that could be used for such a purpose, so you have
> to resort to out-of-band signalling, like boost::Optional.


This is probably a very sensible default in HPC, embedded or otherwise
space-sensitive contexts, but in general application programming I believe
using an explicit sum type is better in a sense of avoiding subtle gotchas,
by making your intent clear in all related declarations, thus potentially
reducing maintenance costs six months down the road.

--
Pavel Lepin
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
What is your experience with JOGL? Mitch Java 5 05-03-2006 01:05 PM
ZoneAlarm has detected a problem with your installation, and therefore has restricted Internet access from your machine for your protection. Don’t panic A Teuchter Computer Support 2 05-19-2005 09:20 PM
OT: Whats the best memory in your experience? AFK Computer Support 3 12-17-2004 10:10 PM
would you please share your experience in ASP.NET printing Edward ASP .Net 2 07-18-2004 04:37 PM
Is there a person who I experience absurd event that experience? PS2 gamer Cisco 4 06-01-2004 07:52 PM



Advertisments