languages like C++ and Rust have an Option type, which is basically an enum/bool with a value.
But I feel like this can have a few problems like:
So why not instead of putting a bool with the value, have a function associated with the type to check if the value returned is valid or not.
for example:
template<typename T, bool(*ISOK)(T&)>
struct Errorable
{
private:
T val;
public:
Errorable(T v)
{
val = v;
}
bool is_ok()
{
return ISOK(val);
}
bool is_err()
{
return !ISOK(val);
}
T unwrap_or(T o)
{
if(ISOK(val))
return val;
return o;
};
T unwrap_forced()
{
return val;
}
};
which can be used like:
bool idx_ok(int& idx)
{
return idx >= 0;
}
Errorable<int, idx_ok> array_idx_of(int *arr, int len, int elm)
{
for(int i = 0 ; i < len ; i++)
{
if(arr[i] == elm)
{
Errorable<int, idx_ok> ok(i);
return ok;
}
}
Errorable<int, idx_ok> err(-1);
return err;
}
and then
int main()
{
int arr[5] = {1, 2, 3, 4, 5};
auto idx = array_index_of(arr, 5, 6);
if(idx.is_ok())
{ ... }
}
sorry if my C++ is bad, I'm a C programmer who needed templates for a sec
The approach you gave requires that the returned object has some sort of invalid state, but not all objects have such a state.
As an example, the C function atoi
converts a C-style string to an int
, and returns 0
if it fails. The problem is that 0
is also a valid integer. Since there's no value of of an int
that can't be the result of successful conversion there's no way to tell just from looking at the return value if atoi
failed or not.
Your Errorable
has the same problem. For instance, if you were to try to write your own atoi
using Errorable
you couldn't do any better than the existing implementation.
The value of std::optional
(and Option types in general) is that they avoid this problem by decoupling the existence of the object from the value of the object. You could write a std::optional<int> my_atoi(const char*)
that can return any value in the entire range of an int
and allows you to determine if the function failed to process its input or not.