Replies: 18 comments
-
For this specific scenario, you can do I also don't know if the compiler can provide this as a general feature without breaking back-compat. This is a bit of a contrived example, but a user today can code something like: struct T
{
public int value;
public static T operator <(int left, T right)
{
return new T();
}
public static T operator >(int left, T right)
{
return new T();
}
public static bool operator <(T left, int right)
{
return (left < right);
}
public static bool operator >(T left, int right)
{
return (left > right);
}
} Which makes the following legal: var unitIndex = new T();
if (0 < unitIndex < 15)
{
} I do think this would be useful, especially for chaining together long sequences of comparisons that are all against a single variable, if the right syntax could be found. |
Beta Was this translation helpful? Give feedback.
-
That's a neat trick if you care about maximum performance. But I don't think it should be used in most code, since I think what the code is supposed to do is heavily obscured. |
Beta Was this translation helpful? Give feedback.
-
@svick, I would hope that anyone who does optimizations like this adds a comment indicating what the corresponding code is. In my own code, I always do something like: if ((uint)(index) > 31) // (index < 0) || (index > 31)
{
ThrowArgumentOutOfRangeException(nameof(index), index);
} Optimizations are great, but only really helpful if you can revisit it 2 years later and understand (easily) why you did it. |
Beta Was this translation helpful? Give feedback.
-
Also, that trick really only works if the lower bound is 0. |
Beta Was this translation helpful? Give feedback.
-
I'm wondering if this could be improved by a library. But I haven't figured out an API that's succinct, readable, and covers at least the three common cases of The best I could come up with is |
Beta Was this translation helpful? Give feedback.
-
Honestly, it would be great if we had some syntax to simplify these types of comparisons. But, as for libraries: static class IntegerUtilities
{
public static bool InRange(int low, int value, int high)
{
return (value >= low) && (value <= high);
}
public static bool InRangeEx(int low, int value, int high)
{
return (value > low) && (value < high);
}
} using static IntegerUtilities;
if (InRange(0, unitIndex, 15)) |
Beta Was this translation helpful? Give feedback.
-
I'd like C# to add a syntax for inequalities maybe we can have a contextual keyword for this? something like this:
I don't know whether |
Beta Was this translation helpful? Give feedback.
-
@tannergooding Yuck that code smells awful. Is it really faster? I can't imagine any application where an "optimization" like that is worth it. Someone asked for this range operator recently in another issue though I can't find it now. |
Beta Was this translation helpful? Give feedback.
-
@MgSam, it removes a jump and a comparison from the generated code. This: static void ValidateInRange(int value, int bounds)
{
if ((uint)(value) > bounds)
{
throw new ArgumentOutOfRangeException();
}
} generates: 00007FFD23D80542 sub esp,20h
00007FFD23D80545 mov ecx,ecx
00007FFD23D80547 movsxd rax,edx
00007FFD23D8054A cmp rcx,rax
00007FFD23D8054D jg 00007FFD23D80555
00007FFD23D8054F add rsp,20h
00007FFD23D80553 pop rsi
00007FFD23D80554 ret
00007FFD23D80555 mov rcx,7FFD23CFAF58h
00007FFD23D8055F call 00007FFD83793A50
00007FFD23D80564 mov rsi,rax
00007FFD23D80567 mov rcx,rsi
00007FFD23D8056A call 00007FFD23CB53E0
00007FFD23D8056F mov rcx,rsi
00007FFD23D80572 call 00007FFD83690120
00007FFD23D80577 int 3 While: static void ValidateInRange2(int value, int bounds)
{
if ((value < 0) || (value > bounds))
{
throw new ArgumentOutOfRangeException();
}
} generates: 00007FFD23D80592 sub esp,20h
00007FFD23D80595 test ecx,ecx
00007FFD23D80597 jl 00007FFD23D805A3
00007FFD23D80599 cmp ecx,edx
00007FFD23D8059B jg 00007FFD23D805A3
00007FFD23D8059D add rsp,20h
00007FFD23D805A1 pop rsi
00007FFD23D805A2 ret
00007FFD23D805A3 mov rcx,7FFD23CFAF58h
00007FFD23D805AD call 00007FFD83793A50
00007FFD23D805B2 mov rsi,rax
00007FFD23D805B5 mov rcx,rsi
00007FFD23D805B8 call 00007FFD23CB53E0
00007FFD23D805BD mov rcx,rsi
00007FFD23D805C0 call 00007FFD83690120
00007FFD23D805C5 int 3 That being said, like most optimizations, it's worth profiling to ensure that it is actually worthwhile to do. But it is also one of those optimizations that is simple enough that the compiler/runtime should be handling it (as is the case with C/C++). |
Beta Was this translation helpful? Give feedback.
-
@MgSam It's used in .Net Core, for example here. And it is faster: one comparison is cheaper than two (and the |
Beta Was this translation helpful? Give feedback.
-
What if we had a syntax for range types, so you could do:
? |
Beta Was this translation helpful? Give feedback.
-
@yaakov-h The first post of this issue asks for open interval (i.e. 1, 2, …, 14). |
Beta Was this translation helpful? Give feedback.
-
@svick It was a general suggestion on how to use another proposal to solve this gripe, not a precise syntactical definition. |
Beta Was this translation helpful? Give feedback.
-
I use an extension method to handle this. static class CompareExtensions
{
public bool IsInRange<T>(this T value, T min, T max) where T : IComparable<T>
{
return min.CompareTo(value) <= 0 && value.CompareTo(max) <= 0;
}
// a non-generic version can also be written with the IComparable interface constraint
} With this, I am able to write While it'll be a nice thing to have built natively into the language (i.e. |
Beta Was this translation helpful? Give feedback.
-
@tannergooding @svick Maybe I could see a compiler doing this, but its absurd for a human to write less legible code that will save at most a few nanoseconds. I'd say its a mistake even having it in .NET Core. The cost of wasting someone's time by leaving them to figure out what its doing (even if just a few seconds) will instantly outweigh by many orders of magnitude any supposed benefits from the implementation. Optimization is finding and removing bottlenecks. |
Beta Was this translation helpful? Give feedback.
-
Yes, and as with any optimization you should profile and target hot-spots for your program. That being said, things like this will almost never show up on a profile tool, but can provide decent savings when applied to an entire code base. This is why I think we need a general |
Beta Was this translation helpful? Give feedback.
-
@MgSam, I take it you haven't looked at the kestrel project much... But in all seriousness, most codebases would not care about the different between 2 comparison vs the single comparison, but framework code that gets called a lot can make it add up. |
Beta Was this translation helpful? Give feedback.
-
You could also just do an extension method to get |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
To represent ranges no we have:
if ( 0 < unitIndex && unitIndex < 15)
I'd like to represent it like
if ( 0 < unitIndex < 15)
The compiler should just translate the sugar syntax to the original
if ( 0 < unitIndex && unitIndex < 15)
Beta Was this translation helpful? Give feedback.
All reactions