This project is read-only.

Allowing comparisons with less code

Topics: C# Language Design
Nov 14, 2014 at 4:35 PM
Edited Nov 14, 2014 at 4:41 PM
I don't know if this has been proposed before, but many times we have to repeat the use of the same variables for conditions like greater than and lower than, or equal (or not equal) than, which may mean lots of typing in some cases, so my suggestions are the following:
1. if( myNumericVariable in {0, 10} ) would translate into if(myNumericVariable > 0 && myNumericVariable < 10) // for any numeric variables like int, float, etc.

2. if( myNumericVariable in {{0, 10} ) would translate into if(myNumericVariable >= 0 && myNumericVariable < 10)

3. if( myNumericVariable in {0, 10}} ) would translate into if(myNumericVariable > 0 && myNumericVariable <= 10)

4. if( myNumericVariable in {{0, 10}} ) would translate into if(myNumericVariable >= 0 && myNumericVariable <= 10)

5. if( myNumericVariable in {{myMinimumValue, myMaximumValue}} ) would translate into if(myNumericVariable >= myMinimumValue && myNumericVariable <= MyMaximumValue) // where myMinimumvalue and myMaximumValue could be variables or constants and, as 1 to 4 above, can be used with combinations of {{, {, }}, or }.

6. if( myEnumVariable == {MyEnum.Value1 || MyEnum.Value2 || ...} ) would translate into if(myEnumVariable == MyEnum.Value1 || myEnumVariable == MyEnum.Value2 || ...)

7. if( myEnumVariable != {MyEnum.Value1 && MyEnum.Value2 && ...} ) would translate into if(myEnumVariable != MyEnum.Value1 && myEnumVariable != MyEnum.Value2 && ...)

8. Same as 5 and 6 but for any reference type with operators like ||, |, &&, & and ^ (and any combination of them).

9. if(myRefVariable ==> {myOtherRefVariable1 || myOtherRefVariable2 || ...} ) would translate into if(myRefVariable.Equals(myOtherRefVariable1) || myRefVariable.Equals(myOtherRefVariable2) || ...)

10. if(myRefVariable !=> {myOtherRefVariable1 && myOtherRefVariable2 && ...} ) would translate into if(!myRefVariable.Equals(myOtherRefVariable1) && (!myRefVariable.Equals(myOtherRefVariable2) && ...)

11. Ditto 8 and 9 but for any combinations of ||, |, &&, & and ^.
These would not demand changes to the CLR afaik, and imho would bring the benefit of better code readability and less typing.
Nov 14, 2014 at 5:28 PM
The in syntax isn't very intuitive. Other languages use that for testing inclusion within a set, not for range comparisons. For the first example I would expect the comparison to only succeed if myNumericVariable was 0 or 10. I'd rather a different keyword be utilized for range comparisons.

This has come up before and usually dismissed as not saving enough typing to be worthwhile. The enum comparisons can be accomplished with Enum.HasFlags. The set operation can be accomplished with Enumerable.Contains:
if ((new [] { 0, 10 }).Contains(myNumericVariable)) { ... }
Nov 14, 2014 at 5:56 PM
public static class RangeComparisonExtensions
{
    public static bool In(int value, int lower, int upper)
    {
        return value > lower && value < upper;
    }
}
Nov 14, 2014 at 6:11 PM
Edited Nov 14, 2014 at 6:22 PM
@Halo_Four: you can still use in with {0 to 10} instead of {0, 10} in order to make it more intuitive. Regarding Enum.HasFlags, who was talking about flags? The set operation is not applicable since I was referring to ranges and your solution implies instantiation of an array, which has nothing to do with "lower than - greater to" comparisons.
1. if( myNumericVariable in {0 to 10} ) would translate into if(myNumericVariable > 0 && myNumericVariable < 10) // for any numeric variables like int, float, etc.

2. if( myNumericVariable in {{0 to 10} ) would translate into if(myNumericVariable >= 0 && myNumericVariable < 10)

3. if( myNumericVariable in {0 to 10}} ) would translate into if(myNumericVariable > 0 && myNumericVariable <= 10)

4. if( myNumericVariable in {{0 to 10}} ) would translate into if(myNumericVariable >= 0 && myNumericVariable <= 10)

5. if( myNumericVariable in {{myMinimumValue to myMaximumValue}} ) would translate into if(myNumericVariable >= myMinimumValue && myNumericVariable <= MyMaximumValue) // where myMinimumvalue and myMaximumValue could be variables or constants and, as 1 to 4 above, can be used with combinations of {{, {, }}, or }.
@PauloMorgado: thanks, I actually have it currently as:
public static class RangeComparisonExtensions
{
    public static bool IsInRange(this int value, int lower, int upper, RangeComparisonType comparisonType)
    {
        switch(comparisonType)
        {
             case RangeComparisonType.Inclusive:
                   return value >= lower && value <= upper;
             case RangeComparisonType.InclusiveLower:
                   return value >= lower && value < upper;
             case RangeComparisonType.InclusiveUpper:
                   return value > lower && value <= upper;
             default:
                   return value > lower && value < upper;
        }
    }
}
But I believe my proposal is more intuitive: if( myNumericVariable in {0 to 10} ) // I have replaced the , to separate it from sets.
Nov 14, 2014 at 6:55 PM
Just in case someone needs it, here is my generic version of IsInRange extension method:
        public enum RangeComparisonType
        {
            Default = 0,
            Exclusive = 0,
            Inclusive,
            InclusiveLower,
            InclusiveUpper
        }

        public static bool IsInRange<T>(this T value, T lower, T upper, RangeComparisonType comparisonType = RangeComparisonType.Default)
            where T: struct, System.IComparable, System.IFormattable, System.IConvertible
        {
            var resultLower = value.CompareTo(lower);
            var resultUpper = value.CompareTo(upper);

            switch (comparisonType)
            {
                case RangeComparisonType.Inclusive:
                    return resultLower >= 0 && resultUpper <= 0;
                case RangeComparisonType.InclusiveLower:
                    return resultLower >= 0 && resultUpper < 0;
                case RangeComparisonType.InclusiveUpper:
                    return resultLower > 0 && resultUpper <= 0;
                default:
                    return resultLower > 0 && resultUpper < 0;
            }
        }
Nov 14, 2014 at 8:50 PM
Edited Nov 14, 2014 at 9:07 PM
@Ultrahead here is a "better" implementation, as your implementation can not be used with class types (for example string)
public enum Clusivity int
{
  exclusive = -1
  inclusive =  0
}

public static bool InBetween<T> ( this T value,
                                       T lower,
                                       T upper,
                                  Clusivity lowerClus = Clusivity.Inclusive,
                                  Clusivity upperClus = Clusivity.Exclusive ) 
  where T : IComparable<T>
{
  return ( lower.ComparedTo( value ) <= lowerClus) &&
         ( value.ComparedTo( upper ) <= upperClus) ;
}
Or you can be possessed by the spirit of Jon Skeet and do the following Invoking Evil Code via the Portal to Hell method
Nov 14, 2014 at 9:30 PM
AdamSpeight2008 wrote:
Or you can be possessed by the spirit of Jon Skeet and do the following Invoking Evil Code via the Portal to Hell method
Wow, that's adorable. Scary, but adorable. I've worked with people who write all of their code like that. :/
Nov 14, 2014 at 9:57 PM
@AdamSpeight2008: nice one!
Nov 14, 2014 at 11:32 PM
Something like this might fit in very nicely with pattern matching.
Nov 17, 2014 at 2:53 PM
Edited Nov 17, 2014 at 2:53 PM
nmgafter wrote:
Something like this might fit in very nicely with pattern matching.
using ...RangePatternMatcher;

...

if (value is Between(lower, upper)) // RangePatternMatcher.Between