I’m very sorry for late reply (it was a hard time for me the last month…) and I really appreciate a lot of inputs!!
Initially, I imagined that there might be some well-known (?) “hack” for using a logical variable for values other than true/false, but it seems it is simply invalid or non-portable, so best to be avoided (even if it may work for some environment).
Among the possible workarounds suggested above, I feel using an integer variable may be the simplest and also easy to use (e.g. assuming 1 → true, 0 → false, -1 → not initialized). This is also nice for interfacing with foreign languages, because I can avoid compatibility issues with boolean types in other languages.
(But a slight downside of this approach may be that, to use it for existing codes, I have to modify if
statements and namelist I/O etc manually. It is of course no problem for new codes if I assume integer variables from the beginning, though.)
Another appealing option may be to define a custom boolean-like type. I will also consider this approach when necessary. (However, for namelist input, it may be somewhat awkward to detect whether the custom variable has been read from a file.)
Because logical
variables typically have 4 bytes, I think there are a lot of “free space” for storing additional information. So, it may be nice if a new compiler can embed more information for free bits (?) somehow, to enable further check (such as user initialization) at the compiler level.
Just for fun, I have also searched the net to see how other languages might deal with this problem. Though I’ve never used it, Nullable
might provide such utility for value types (though not very sure…)
Primitive types such as integers and Booleans cannot generally be null, but the corresponding nullable types (nullable integer and nullable Boolean, respectively) can also assume the NULL value. This can be represented in ternary logic as FALSE,NULL,TRUE as in three-valued logic.
Another interesting feature I came across is alias this
in the D language, which allows to define a boolean-like custom type that can be used without modifying existing codes (while allowing to have additional fields to check initialization, for example). An example code may be like this (Compiler Explorer here):
struct Mybool
{
bool myflag = true;
alias myflag this; // forward any access to "myflag" by default
bool inited = false;
}
void main()
{
import std.stdio;
Mybool b; // custom boolean variable
writeln( "b = ", b ); // can be output directly
writeln( "b.myflag = ", b.myflag );
writeln( "b.inited = ", b.inited );
if ( b ) writeln( "(b = true)" ); // can be tested directly
if ( ! b ) writeln( "(b = false)" );
assert( b.inited ); // raises error because b is not inited
writeln( "ok" );
}
$ gdc-11 test.d && ./a.out
b = true
b.myflag = true
b.inited = false
(b = true)
core.exception.AssertError@test.d(28): Assertion failure