Page 1 of 1

bool? can be counterintuitive

PostPosted: Fri Apr 11, 2008 1:40 pm
by khjklujn
I don't think this one is a bug, but the behavior of nillable bools in implicit testing is something that could lead to the generation of very subtle bugs.
class Bob
shared
def eval(t as bool?) as String
return '[t] ==> ' + if(t, 'true', 'false')

def evalNot(t as bool?) as String
return 'not [t] ==> ' + if(not t, 'true', 'false')

def main
print Bob.eval(true) # true ==> true
print Bob.eval(false) # false ==> true
print Bob.eval(nil) # nil ==> false
print
print Bob.evalNot(true) # not true ==> false
print Bob.evalNot(false) # not false ==> false
print Bob.evalNot(nil) # not nil ==> true

Not that nillable bools are used all that frequently, but when they are, it would probably be best to remind the programmer that it's not the boolean value that will be implicitly tested by generating an error or warning.

Applied ignorance combined with quick an dirty hacking led me to insert the following lines at line 2114 in Expr.cobra (in TestExpr._bindImp):
_
if type.theWrappedType inherits DynamicType
_sharpTreatment = SharpTreatment.InvokeRuntime

+ else if type.theWrappedType is .compiler.boolType
+ trace type
+ _sharpTreatment = SharpTreatment.CompareToNull

else
_sharpTreatment = SharpTreatment.CompareToNull

the results of which suggest that it might be a good candidate for such a verification to take place.

Re: bool? can be counterintuitive

PostPosted: Fri Apr 11, 2008 6:26 pm
by Charles
I agree that this is weirdness. The one time I got stung by something like this was with "dynamic?" which was only checking for non-nil. So whereas "dynamic" would check for "true" or "false" and do the intuitive thing, "dynamic?" would not. This applied to numbers as well (zero vs. non-zero). I decided that "dynamic" in any form was extra special and fixed it so that "dynamic?" now goes the extra mile: After checking for non-nil, it then acts like "dynamic" and checks further. In practice, this works out much better.

So what to do with "bool?"?. If left as is, the behavior is not only potentially counterintuitive, but inconsistent with "dynamic?". Then again maybe we can live with that (bool? types are rare) and a warning is sufficient.

If you're up to it, see also: Truthfulness

Re: bool? can be counterintuitive

PostPosted: Fri Apr 11, 2008 9:25 pm
by khjklujn
Yeah, I've been scratching my head over it. I can only think of two reasons I would use a 'bool?'. The first is for lazy evaluation:
pro hasArrived as bool?
get
if _hasArrived is nil
_hasArrived = .something.thatTakesAReallyLongTimeToDetermine
return _hasArrived
set
_hasArrived = value

The other is inherited values in a tree structure:
# assuming the tree is rooted to nil and the default is false
pro isPretty as bool?
get
if .parent and _isPretty is nil
return .parent.isPretty
else if not .parent
return false
else
return true
set
_isPretty = value

In neither case would I be naturally inclined return a nil. The only reason the property is nillable is to be able to force a reevaluation. I guess the first might possibly return a nil to indicate a timeout or something, though I'd probably be more likely to raise an exception in that case.

So, contrary to the argument I thought I was going to make, I actually think I would prefer that they behaved like 'dynamic?'. That way, given the way I would typically use them, I wouldn't have to care whether or not some property defined in another file was nillable.

Re: bool? can be counterintuitive

PostPosted: Sun Apr 13, 2008 10:30 am
by Charles
Yeah, I think I agree with you. If "dynamic?" is not truthful for values like 0 and false, then types like "bool?" and "int?" should act the same for consistency. This applies to char? and all numeric types as well.

And there's no loss of consistency with non-primitive reference types which are considered truthful.

Re: bool? can be counterintuitive

PostPosted: Sun Nov 16, 2008 2:05 pm
by Charles
This is now fixed. See ticket:5 which also has a link to the changeset which then includes the test cases.

Re: bool? can be counterintuitive

PostPosted: Fri Jan 16, 2009 9:02 am
by jonathandavid
Chuck wrote:This is now fixed. See ticket:5 which also has a link to the changeset which then includes the test cases.



I hope some day we will have the possibility to reproduce this behavior in user classes. This way, if for instance I write a BigInt class, I can make "if x" where x is an instance of BigInt?, behave like a primitive int?, (i.e., first it's checked for nilness and then for "zero-ness"):

class BigInt

# ...

cue truth as bool # will be used "if x" and "if not x". Note that "as bool" part is redundant. We could make it optional
return this <> BigInt(0)


class Program
def main is shared
x as BigInt?
if x # false, is nil
pass

x = BigInt(0)
if x # false, is not nil but zero
pass

x = BigInt(1)
if x # true, is not nil and non-zero
pass


This way, when the compiler encounter "if x" where x is of type BigInt?, it realizes that BigInt has the "truth" cue and generates the following code:

if x is not nil and x.truth        # this is what "if x" translates to
# whatever


Conversely, "if not x" would translate to "if x is nil or not x.truth". I think there are languages like Ruby that allow you to provide an alternative method to test falseness (as in "if not x"), but I don't see the use when one can simply assume that "not x" amounts to "not x.truth".