Automatic conversion of bool to int

In irb we have:

1 + true

=> TypeError: true can’t be coerced into Fixnum

In rbx we have:

1 + true

=> 2

There are the following methods for + in Fixnum:

   public static object Add(int self, int other)

public static double Add(int self, double other)

public static object Add(CodeContext/!/ context, object self, object
other)

I expected that passing a bool into + operator would have ended up at
the
third overload, which would give the correct behaviour when it tries to
coerce on the bool. But it actually gets mapped to the first overload
and
there is an implicit conversion of true to 1. You can see this in the
resulting AST dump:

(FixnumOps.Add)(

(.bound $arg0),

(Converter.ConvertToInt32)(

    (Object)(.bound $arg1),

),

)

After some digging I found this method in Ruby.Runtime.Converter:

    private static bool HasImplicitNumericConversion(Type fromType, 

Type
toType) {

        if (fromType.IsEnum) return false;



        if (fromType == typeof(BigInteger)) {

            if (toType == typeof(double)) return true;

            if (toType == typeof(float)) return true;

            if (toType == typeof(Complex64)) return true;

            return false;

        }



        if (fromType == typeof(bool)) {

            if (toType == typeof(int)) return true;

            return HasImplicitNumericConversion(typeof(int), 

toType);

        }



        ...

Here you can see that bool is automatically converted to an int. Is
this
correct behaviour? I appreciate that we can take any non-nil value as
true
and nil as false but not the other way round.

ASIDE: In fact all three methods are added as “Applicable Targets” but
the
int version gets there first. Is there a heuristic for the order in
which
overloads are considered?

Regards,

Pete

The conversions are wrong. In fact, they are quire arbitrary (the code
is in fact partly copied from IronPython). We have an item on our todo
list to reimplement them from scratch.

Tomas

From: [email protected]
[mailto:[email protected]] On Behalf Of Peter Bacon
Darwin
Sent: Friday, January 11, 2008 5:10 AM
To: [email protected]
Subject: [Ironruby-core] Automatic conversion of bool to int

In irb we have:

1 + true
=> TypeError: true can’t be coerced into Fixnum

In rbx we have:

1 + true
=> 2

There are the following methods for + in Fixnum:

   public static object Add(int self, int other)

public static double Add(int self, double other)
public static object Add(CodeContext/!/ context, object self, object
other)

I expected that passing a bool into + operator would have ended up at
the third overload, which would give the correct behaviour when it tries
to coerce on the bool. But it actually gets mapped to the first
overload and there is an implicit conversion of true to 1. You can see
this in the resulting AST dump:

(FixnumOps.Add)(
(.bound $arg0),
(Converter.ConvertToInt32)(
(Object)(.bound $arg1),
),
)

After some digging I found this method in Ruby.Runtime.Converter:

    private static bool HasImplicitNumericConversion(Type fromType, 

Type toType) {
if (fromType.IsEnum) return false;

        if (fromType == typeof(BigInteger)) {
            if (toType == typeof(double)) return true;
            if (toType == typeof(float)) return true;
            if (toType == typeof(Complex64)) return true;
            return false;
        }

        if (fromType == typeof(bool)) {
            if (toType == typeof(int)) return true;
            return HasImplicitNumericConversion(typeof(int), 

toType);
}

        ...

Here you can see that bool is automatically converted to an int. Is
this correct behaviour? I appreciate that we can take any non-nil value
as true and nil as false but not the other way round.

ASIDE: In fact all three methods are added as “Applicable Targets” but
the int version gets there first. Is there a heuristic for the order in
which overloads are considered?

Regards,
Pete

And regarding your applicable targets question: Yes, infact there’s two
ways to specify the preference, hopefully that’ll go back down to 1
someday :). The ActionBinder provides the conversion helpers and has
two methods related to this. The first is the PreferConvert method
where you’re passed two types and you select which one you want. The
2nd (and more likely to survive long term) is SelectBestConversionFor
where you get the actual type passed in, and the two types that are
candidates for method selection, as well as the current NarrowingLevel.
Currently we first consult SelectBestConversionFor and the last thing we
do is check PreferConvert if we still haven’t figured out the best
method.

This is done on a parameter by parameter basis and so all of the
parameters need to be better than the parameters for another method
otherwise we’ll have an ambiguous match.

From: [email protected]
[mailto:[email protected]] On Behalf Of Tomas M.
Sent: Friday, January 11, 2008 9:16 AM
To: [email protected]
Subject: Re: [Ironruby-core] Automatic conversion of bool to int

The conversions are wrong. In fact, they are quire arbitrary (the code
is in fact partly copied from IronPython). We have an item on our todo
list to reimplement them from scratch.

Tomas

From: [email protected]
[mailto:[email protected]] On Behalf Of Peter Bacon
Darwin
Sent: Friday, January 11, 2008 5:10 AM
To: [email protected]
Subject: [Ironruby-core] Automatic conversion of bool to int

In irb we have:

1 + true
=> TypeError: true can’t be coerced into Fixnum

In rbx we have:

1 + true
=> 2

There are the following methods for + in Fixnum:

   public static object Add(int self, int other)

public static double Add(int self, double other)
public static object Add(CodeContext/!/ context, object self, object
other)

I expected that passing a bool into + operator would have ended up at
the third overload, which would give the correct behaviour when it tries
to coerce on the bool. But it actually gets mapped to the first
overload and there is an implicit conversion of true to 1. You can see
this in the resulting AST dump:

(FixnumOps.Add)(
(.bound $arg0),
(Converter.ConvertToInt32)(
(Object)(.bound $arg1),
),
)

After some digging I found this method in Ruby.Runtime.Converter:

    private static bool HasImplicitNumericConversion(Type fromType, 

Type toType) {
if (fromType.IsEnum) return false;

        if (fromType == typeof(BigInteger)) {
            if (toType == typeof(double)) return true;
            if (toType == typeof(float)) return true;
            if (toType == typeof(Complex64)) return true;
            return false;
        }

        if (fromType == typeof(bool)) {
            if (toType == typeof(int)) return true;
            return HasImplicitNumericConversion(typeof(int), 

toType);
}

        ...

Here you can see that bool is automatically converted to an int. Is
this correct behaviour? I appreciate that we can take any non-nil value
as true and nil as false but not the other way round.

ASIDE: In fact all three methods are added as “Applicable Targets” but
the int version gets there first. Is there a heuristic for the order in
which overloads are considered?

Regards,
Pete

Since you are going to reimplement the conversions from scratch at some
point, can I offer the following patch to fix the particular bool to int
conversion problem for now?

It is also pretty trivial.

Regards,

Pete

From: [email protected]
[mailto:[email protected]] On Behalf Of Tomas M.
Sent: Friday,11 January 11, 2008 17:16
To: [email protected]
Subject: Re: [Ironruby-core] Automatic conversion of bool to int

The conversions are wrong. In fact, they are quire arbitrary (the code
is in
fact partly copied from IronPython). We have an item on our todo list to
reimplement them from scratch.

Tomas

From: [email protected]
[mailto:[email protected]] On Behalf Of Peter Bacon
Darwin
Sent: Friday, January 11, 2008 5:10 AM
To: [email protected]
Subject: [Ironruby-core] Automatic conversion of bool to int

In irb we have:

1 + true

=> TypeError: true can’t be coerced into Fixnum

In rbx we have:

1 + true

=> 2

There are the following methods for + in Fixnum:

   public static object Add(int self, int other)

public static double Add(int self, double other)

public static object Add(CodeContext/!/ context, object self, object
other)

I expected that passing a bool into + operator would have ended up at
the
third overload, which would give the correct behaviour when it tries to
coerce on the bool. But it actually gets mapped to the first overload
and
there is an implicit conversion of true to 1. You can see this in the
resulting AST dump:

(FixnumOps.Add)(

(.bound $arg0),

(Converter.ConvertToInt32)(

    (Object)(.bound $arg1),

),

)

After some digging I found this method in Ruby.Runtime.Converter:

    private static bool HasImplicitNumericConversion(Type fromType, 

Type
toType) {

        if (fromType.IsEnum) return false;



        if (fromType == typeof(BigInteger)) {

            if (toType == typeof(double)) return true;

            if (toType == typeof(float)) return true;

            if (toType == typeof(Complex64)) return true;

            return false;

        }



        if (fromType == typeof(bool)) {

            if (toType == typeof(int)) return true;

            return HasImplicitNumericConversion(typeof(int), 

toType);

        }



        ...

Here you can see that bool is automatically converted to an int. Is
this
correct behaviour? I appreciate that we can take any non-nil value as
true
and nil as false but not the other way round.

ASIDE: In fact all three methods are added as “Applicable Targets” but
the
int version gets there first. Is there a heuristic for the order in
which
overloads are considered?

Regards,

Pete