Skip to content

Existing behavior of AndAlso and OrElse in DLR is wrong #83350

@ds1709

Description

@ds1709

Description

As described on MSDN, in DLR operations AndAlso and OrElse represent pairs of IsFalse/And and IsTrue/Or. This is becoming a problem when I'm trying to implement some zero/non-zero boolean logic.

For example, I have some dynamic object over integer. Zero value is false, non-zero is true. In c++ it works like this:

int a = 10;
int b = 20;
cout << (a && b); // out '1', coz 10 and 20 both are non-zero values
cout << (a & b); // out '0', coz it's a result of bitwise and

With current implementation of DLR I can't implement such behavior coz when I binding binary operation, I got And/Or operation type instead of expected AndAlso/OrElse. So I dont know, was it logical or bitwise operation.

Reproduction Steps

Define this simple class:

public sealed class MetaUInt32 : DynamicObject
{
    private readonly uint value;

    public MetaUInt32(uint value)
    {
        this.value = value;
    }

    public override bool TryUnaryOperation(UnaryOperationBinder binder, out object? result)
    {
        if (binder.Operation == ExpressionType.IsFalse)
        {
            result = (value == 0u);
            return true;
        }
        else
        {
            return base.TryUnaryOperation(binder, out result);
        }
    }

    public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object? result)
    {
        if (arg is MetaUInt32 m && binder.Operation is ExpressionType.And)
        {
            result = new MetaUInt32(value & m.value);
            return true;
        }
        else
        {
            return base.TryBinaryOperation(binder, arg, out result);
        }
    }
}

And then use it like this:

dynamic a = new MetaUInt32(10);
dynamic b = new MetaUInt32(20);
var c = a && b;

Expected behavior

Variable c must be instance of MetaUInt32 over 1, because a and b are non-zero values (10 and 20).

Actual behavior

Variable c is instance of MetaUInt32 over 0, because it's a result of bitwise and over 10 and 20.

Regression?

No response

Known Workarounds

As workaround, I can implement casting of MetaUInt32 to boolean and then make boolean binary operation over cast results, like this:

dynamic c = new MetaUInt32((bool)a && (bool)c ? 1 : 0);

It's not too hard to do, but if your dynamic class also implements bitwise logic, you must keep in mind, that boolean binary logic works correctly only if you cast your object to boolean first.

Also it's becoming a problem when you are working with dynamic expressions (System.Linq.Expressions.Expression.Dynamic). If you'are implementing binary operation, you must have special case for AndAlso/OrElse operations, because them are not supported by BinaryOperationBinder.

Configuration

No response

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions