Improvement on 'return -1' for representing failure of a function

I have a function whose 'argument' and 'return type' will always be a unsigned (positive) integer.

For example, if we want to find index of fabonnaci series, the index(return type) will always be unsigned(indexs of an array are always positive). Also all elements in a fabonnaci series are unsigned(Fibonacci starts from 0 and goes onward to 0,1,1,2,3,5.. ) so the input argument will always be unsigned.
So i keep the return type 'unsigned int' like in the below code.

1
2
3
4
5
6

unsigned int findIndex(unsigned int fabonnaci_value)
{

}


In case this function does not successfully find the index for input(e.g if we search the index for value '4' which is not a part of fabonnaci, we won't have a valid index to return) what should i return. Normally I see

1
2
3

return -1;


in case of failed function. But just for this one situation, i think it is not efficient to change the return type of function to 'int' from 'unsigned int' as the range of output values is decreased drastically.

What should i do here as an alternative? I want to know how these situations are handled/justified by professionals?
Last edited on
The two best solutions:
- easiest solution is to return an int, where -1 would mean 'failure'.

- the most readable is to return std::pair<int, bool>

Other:
The third solution is to return a structure.

The fourth solution would be to return the error code or the result as a reference through one of the function's parameters.

You could also throw an exception.
Yes, it is possible to use exceptions, but that is not really recommended. Like, exceptions should be used for exceptional circumstances, for example when your building is on fire.
Thanks for the suggestions.
Kevin C wrote:
Yes, it is possible to use exceptions, but that is not really recommended.
According to whom?

According to Herb Sutter, an exception is appropriate, with caveat.
http://www.drdobbs.com/when-and-how-to-use-exceptions/184401836

The caveat is this: is it an error for your function to receive a non-Fibonacci number as argument? That is, should the caller be required to only pass Fibonacci numbers?

If it is, then use an exception.

If it is not, then provide a different kind of result, such as 0 or std::optional.
closed account (48T7M4Gy)
Can an event that happens most times a program is run be considered
exceptional? Can an event that is planned for and handled be considered an error? The answer to
both questions is ‘‘yes.’’ ‘‘Exceptional’’ does not mean ‘‘almost never happens’’ or ‘‘disastrous.’’ Bjarne Stroustrup The C++ Programming Language, 4th Edition-Addison-Wesley Professional (2013)
Ok, I would agree that if a function's precondition has not been satisfied, it makes sense to throw an exception as some kind of run-time error management policy.

I don't see any other valid cases for throwing an exception in functions such as the one given.

If there is no precondition that the input has to be a fib number, than I don't see much sense in using exceptions here.
And what should be an appropriate return type in case all int (signed and unsigned) are valid return values. What value should represent failure in this case?
If there is no precondition that the input has to be a fib number, than I don't see much sense in using exceptions here.
Agreed. For this kind of function, it is reasonable that the user will not know whether or not the argument is a Fibonacci number, so one of the return values should be "not a Fibonacci number".

And what should be an appropriate return type in case all int (signed and unsigned) are valid return values. What value should represent failure in this case?
This is where your algorithm design matters; you can typically avoid such situations by careful design.

However, the problem does exist, and there are various ways to handle it.

You could choose a return value with an obvious conflict. For our Fibonacci example, returning zero for any argument other than 1 would be a good signal that the argument was invalid.

You could return a separate value.
bool findFibonacciIndex( unsigned n, unsigned& index )
(The standard streams use this kind of logic, so you can say things like while (getline(cin,s)) ....)

You could return a boost::optional/std::experimental::optional:
http://www.boost.org/doc/libs/release/libs/optional/doc/html/index.html

Or you could throw an exception.

What works best is up to your application requirements.
closed account (48T7M4Gy)
Yeah why not take advantage of 0 as the first unsigned integer. The first Fibonnaci number is 0, but it is index number 1 in the series.

( 0 is coincidentally boolean false IIRC.)
It also solves the conflict between Fib(0) and Fib(1) both being 1.
closed account (48T7M4Gy)
Interestingly while Fibonacci numbers 'normally' start at 1. As mentioned online in a few places it is apparently a modern thing that it is equally acceptable to start at 0. But whatever the starting point the returning 0 logic remains intact, provided the index starts at 1.

A
000045 Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.


https://oeis.org/A000045
http://www.wolframalpha.com/input/?i=fibonacci+series
Last edited on
I think that's because it is more commonly recognized these days that the Fibonacci sequence is a Lucas sequence of the form Un(1,-1), so that

U0 = 0
U1 = 1
U2 = 1
U3 = 12 - -1 = 2
U4 = 13 - 2(1)(-1) = 3
etc
Thanks for all the replies.
Topic archived. No new replies allowed.