flag and variable, or variable w/ reserved value?

Started by
8 comments, last by l0calh05t 8 years, 4 months ago

flag and variable, or variable w/ reserved value?

which is better?

all the time, i come across the "pattern" of a variable storing a value, and a boolean or reserved value saying whether its in effect or not.

or a boolean or reserved value indicating "none" or "N/A" or "don't care".

an example using a reserved value:

current_weapontype_ID_number // an object_type ID number, or -1 for none.

an example using a variable and a boolean:

dropped_object[n].data[0] // generic var. for travois: 0=not carried, 1=carried.

dropped_object[n].data[1] // generic var. for travois: ID number of player carrying the travois

other than the obvious fact that a flag requires a second variable, are there any advantages one way or the other?

i run into this "pattern" a lot, and use both methods. but i would like to establish a coding policy one way or the other.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

Advertisement

I would default to using a well-defined sentinel value for this (use a named constant, e.g. const int InvalidObjectId = -1). Managing a single value is always easier than managing two that need to be kept in sync.

The exception would be if you absolutely require the full range of values that the variable provides.

I guess you could also use a struct that has both the id and the "is valid" flag, and class invariants to ensure the state is consistent.

It depends on the situation.

Sometimes a key value or sentinel case is better. It may be easier, it may be faster, it may be less work to maintain.

Other times a separate flag is better. It may be easier, it may be faster, it may be less work to maintain.

The case of NULL is interesting because it follows both. The ability to have a "not a value" value is great in some contexts. However, the constant check against null has a serious cost.

In many situations in games it is better to not test against NULL at all, always pointing values to a valid placeholder. It still serves as a sentinel value of sorts, but using it is not catastrophic. Anything using the placeholder gets flagged, and in final builds the placeholder is replaced with an invisible object. Following a pointer to a placeholder is valid, following the null pointer is really bad.

Other times it can be good to have an external flag. If the cost of checking against an empty flag, or a dirty flag, or some other marker is expensive then having a separate flag can be a great solution. Especially in polymorphic situations, the cost of checking against a known base-class flag is small relative to the cost of virtual dispatch. Of course it is better if you can avoid the tests fully, but if you have options between a fast flag and a slower process, the fast flag is a good thing.

It is all up to context.


I would default to using a well-defined sentinel value for this (use a named constant, e.g. const int InvalidObjectId = -1).

that sounds like one vote for reserved values.


Managing a single value is always easier than managing two that need to be kept in sync.

a good point.


The exception would be if you absolutely require the full range of values that the variable provides.

seldom the case. variables are often array indices, stored in ints, which leaves negative numbers free for use as reserved values, similar to a function that returns a non-negative value on success, or a reserved negative value as an error code.


I guess you could also use a struct that has both the id and the "is valid" flag, and class invariants to ensure the state is consistent.

that _would_ be more bullet proof that relying on coder discipline to keep them in sync. "kid safe" code isn't really a concern here though. guess i'm looking more for efficiency - less code entry, simpler algos, that kind of stuff. right now, its seems to be a rather even trade off between the extra code and comments for a flag vs a reserved value.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

Of course, there is a Boost library for it (http://www.boost.org/doc/libs/1_58_0/libs/optional/doc/html/index.html), but I have never used it.


The case of NULL is interesting because it follows both. The ability to have a "not a value" value is great in some contexts. However, the constant check against null has a serious cost.

In many situations in games it is better to not test against NULL at all, always pointing values to a valid placeholder. It still serves as a sentinel value of sorts, but using it is not catastrophic. Anything using the placeholder gets flagged, and in final builds the placeholder is replaced with an invisible object. Following a pointer to a placeholder is valid, following the null pointer is really bad.

fortunately, i don't have to deal with such issues. i use statically allocated arrays in the data segment, combined with code designed to prevent the need for range checks (to the maximum extent possible). for the stuff i'm making its "good enuf" to "geter dun".


Other times it can be good to have an external flag. If the cost of checking against an empty flag, or a dirty flag, or some other marker is expensive then having a separate flag can be a great solution. Especially in polymorphic situations, the cost of checking against a known base-class flag is small relative to the cost of virtual dispatch. Of course it is better if you can avoid the tests fully, but if you have options between a fast flag and a slower process, the fast flag is a good thing.

a valid consideration. again, i'm lucky in that i don't have to deal with such things. i'm pretty much PODs and procedural code, organized into ADTs. i'm talking about simple cases, where the difference between checking a flag and a reserved value is negligible.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

I always try to reduce the number of variables, so if possible, I fold the "not a value" value into the variables I must have anyway, using a named constant to indicate the absence of a value (sometimes there are even several such values).

The exceptions are the cases where you don't have room, eg a 16bit unsigned value where all 65536 values are valid.

Edit: Perhaps this is more an issue in return values of functions, where you don't have space to easily add a second value? (at least in some of the languages).


Of course, there is a Boost library for it

seems like there's a boost library for everything these days! <g>

if i can do something trivial like this in-house as fast as i can with a lib, i'll always go in-house.

cobbling a game together with as many 3rd party libs vs in-house code as possible always struck me as a rather house-of-cards way to build things. don't get me wrong, i'm a formally trained engineer, and understand the value of systems engineering from off-the-shelf components, i guess its just that i've seen so many games get it wrong. then again, i guess if they can't write the lib themselves, what should i expect? them that can, do. them that can't, teach, them that can't teach, administrate - that kind of concept.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php


I always try to reduce the number of variables, so if possible, I fold the "not a value" value into the variables I must have anyway, using a named constant to indicate the absence of a value (sometimes there are even several such values).

that would be two votes favoring reserved value when possible.

i tend to use reserved value myself. its the natural solution that first comes to mind (at least for me).

in my second example above, in that case, i already had a generic int data[5] array ready for use in an object struct, so i used the first var as the flag, and the second as the value.


The exceptions are the cases where you don't have room, eg a 16bit unsigned value where all 65536 values are valid.

yes. it sounds like for simple cases, here a flag is called for, and in all other cases, reserved values will suffice. perhaps that should be the coding policy. obviously this would not include cases where checking one vs the other is non-trivial (as mentioned by frob).


Edit: Perhaps this is more an issue in return values of functions, where you don't have space to easily add a second value? (at least in some of the languages).

i was just adding a routine to return the index of a travois world object carried by player N, or negative 1 for none. and i noticed that travois objects use data[0] as a flag, and data[1] as the value. and this question of whether flag or reserved value is better has been bugging me now for a few weeks. one of those things that just occurs to you that you never really gave much thought to before on a "company wide coding policy" basis. thus my OP.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

This blog post may be of interest: https://akrzemi1.wordpress.com/2015/07/15/efficient-optional-values/

This topic is closed to new replies.

Advertisement