Replies: 32 comments
-
Duplicate of dotnet/roslyn#119 |
Beta Was this translation helpful? Give feedback.
-
Not quite. This is a type, that has some compat with a full-range int. All the fun type checking can be applied to this at compile time, rather than the run-time exception that 119 proposes. I thought Module 2 had a range type, but I can't find it. So the constrained range (CR) int may be a subtype of an int. with overridden operators. Anything that can take an int, can take a CR int. To convert an int to a CR int requires a range check. See the null object mitigation work that MADS is talking about for inspiration on this conversion. CR ints are equivalent (the same type) if their range is the same. |
Beta Was this translation helpful? Give feedback.
-
I'd suggest writing an analyzer which can use annotations to denote range. Having it supported directly in the compiler at this time I don't think makes sense. It would make more sense included in the larger proposal of method contracts. |
Beta Was this translation helpful? Give feedback.
-
@codecore why then not add types
Current code contracts allow static contract checking. I suppose that this proposal would be done in the same manner. |
Beta Was this translation helpful? Give feedback.
-
I think this may be more of a duplicate of #413. |
Beta Was this translation helpful? Give feedback.
-
This looks much like 413. @scottdorman makes a good case for it. I see applications for CR types where your standard numeric types are just too unbounded. I've struggled with Latitude and Longitude and CR would be an answer. https://github.com/codecore/Functional/blob/master/Functional/GPS/LocationContract.cs |
Beta Was this translation helpful? Give feedback.
-
Method contracts seems to cover this. And being those are unlikely to happen anytime soon, why not just use a helper method? public void Foo(int i)
{
Assert.Between(i, 0, 42);
...
} |
Beta Was this translation helpful? Give feedback.
-
Yes, this seems like it would be covered by #413. @MgSam, I don't see how method contracts or your example of using an Assert actually cover this scenario. Yes, they may cause the runtime to fail if the value is outside of the allowed bounds, but have no influence on compile time checking and don't actually describe the intent. Having a constrained integer type clearly defines that the type should only ever have values within that range and makes that part of the actual type definition. @HaloFour, an analyzer doesn't solve the problem here. I also don't see how method contracts would cover this either. @codecore Yes, constrained types would solve the unbounded issues you have with the Latitude and Longitude pretty cleanly and clearly define the value ranges. |
Beta Was this translation helpful? Give feedback.
-
This proposal doesn't say anything about compile time range checking. Seems like that would be of extremely limited utility. How often are you hard-coding values that you need a compiler to range check for you? |
Beta Was this translation helpful? Give feedback.
-
@MgSam No, this proposal doesn't, but #413 does and this is, by and large, a duplicate (or at least a subset) of what's proposed there. As for how often compile time checking would be useful, for me now, not so much any more, but when I was working in the defense industry it was needed/used all of the time to prevent damage to hardware. (See the example in #413, but think about software that controls a gimbal motor. The hardware can only travel a certain range before it suffers physical damage. Having constrained types prevents the software from allowing variables to approach those limits and also clearly defines the scope/range of the type.) |
Beta Was this translation helpful? Give feedback.
-
I completely agree that a constrained integer type has uses, but it seems like it needs to be a runtime constraint. And it certainly doesn't need a special syntax. |
Beta Was this translation helpful? Give feedback.
-
An analyzer is necessary to enforce the constraint at compile time rather than just letting it fail at run time, which is a stated goal of this proposal (at least per this comment). That would necessitate flow analysis that would be at least as complicated as that applied to non-nullable references, if not worse since these "constrained values" can continually narrow their ranges and the compiler would have to track every possibility that the value could be out of bounds. Method contracts have the same problem. To be particularly useful they need static analysis during compile time to validate arguments. Without that and the metadata to facilitate that all of those proposals are frankly a waste of time. We don't need yet another syntax that will do nothing more than run time validation of arguments that bakes in some ideology as to how to react to invalid values. I don't see how this proposal could be implemented effectively beyond an attribute of range metadata and flow analysis. The only other possibility would be that the compiler would have to spit out a |
Beta Was this translation helpful? Give feedback.
-
@codecore we discussed something similar back then that doesn't require new syntax using attributes, can check the discussion here but even this was controversial. I really think that if you go this route you may need a very convincing use-case that isn't a niche for the design team to even consider something like this because currently, it looks like they don't seems to like the notion of contracts or well, they think that it's too verbose and maybe intrusive. |
Beta Was this translation helpful? Give feedback.
-
I think This is no different from thinking of Really I think this is where type aliases make sense: type UnitIndex = int[0..15]; public static ManagerWarning GetManagerWarningForUnit(UnitIndex unitIndex) {...}
...
GetManagerWarningForUnit(-1); // Not allowed, -1 is not convertible to int[0..15]
GetManagerWarningForUnit(0); // Allowed, 0 is convertible to int[0..15]
int i = 1;
GetManagerWarningForUnit(i); // Not allowed, no implicit cast from int to int[0..15]
UnitIndex ui = 2;
GetManagerWarningForUnit(ui); // Allowed
int[0..15] i0_15 = 3;
GetManagerWarningForUnit(i0_15); // Allowed
int[4..5] i4_5 = 4;
GetManagerWarningForUnit(i4_5); // Allowed, int[4..5] is a subset of int[0..15] I'm not sure there is really a need for flow analysis. |
Beta Was this translation helpful? Give feedback.
-
Having used ranged integer types in Ada, back in the day, I can say with confidence that such types are way more trouble than they are worth. Sure it gives built in range checking, but it then leads to a plethora of incompatible Also, with this proposal, the ranges are being expressed with "magic numbers", directly at the point of use, this would create a maintenance headache if those ranges had to change. So a definite 👎 from me. |
Beta Was this translation helpful? Give feedback.
-
@svick the type of |
Beta Was this translation helpful? Give feedback.
-
In some way an As you can see these 2 problems can be solved using an analyzer that "magically" creates the struct types the problem is if for use of low level code you want to do the next pass and create a struct using them for example: struct DoubleView
{
Bit11 Fraction;
Bit52 Fraction;
Bit1 Sign;
} the size of DoubleView should be 64 bit (same size of a double) to be useful but the compiler has yet no support for this. |
Beta Was this translation helpful? Give feedback.
-
@Pzixel You are treating my use as an integer with rules that constrain the range, where I am proposing a type that doesn't require any rules. The only gotcha is when you want to stick a regular integer into the constrained range integer. There are easy solutions for that. This is a type that acts just like a regular integer over a specific range. When things start getting out of that range at runtime, we have overflow, underflow, and argument range exceptions available. Also, the contract solution you propose requires verbose contracts on each function that takes it, while the CR integer type I propose has no such requirement. |
Beta Was this translation helpful? Give feedback.
-
The existing signatures are public static sbyte Max(sbyte val1, sbyte val2)
public static byte Max(byte val1, byte val2)
public static short Max(short val1, short val2)
public static ushort Max(ushort val1, ushort val2)
public static int Max(int val1, int val2)
public static uint Max(uint val1, uint val2)
public static long Max(long val1, long val2)
public static ulong Max(ulong val1, ulong val2)
public static float Max(float val1, float val2)
public static double Max(double val1, double val2)
public static Decimal Max(Decimal val1, Decimal val2) I would expect it to use the |
Beta Was this translation helpful? Give feedback.
-
If the argument is typed as |
Beta Was this translation helpful? Give feedback.
-
I presume |
Beta Was this translation helpful? Give feedback.
-
Anyway, let's say that a new method were added to the API. What signature would it have? I think it would need to rely on Union/Or types from #399, as well as some new constraint syntax: public static T|U Max(T val1, U val2) where T : long, U : long |
Beta Was this translation helpful? Give feedback.
-
( |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
I made the same proposal in #1198 but I think it is the generic form. |
Beta Was this translation helpful? Give feedback.
-
So, there are 4 possible ways to do it:
Sure we all want some syntax to simplify validation codes. |
Beta Was this translation helpful? Give feedback.
-
Assuming you mean Modula2, it's called a subrange type (also called that in Pascal): |
Beta Was this translation helpful? Give feedback.
-
And here it is.... a constrained range int. |
Beta Was this translation helpful? Give feedback.
-
@codecore I'm not sure that array ranges is the same thing as this request. |
Beta Was this translation helpful? Give feedback.
-
That refers to #185. It doesn't constraint the possible values of an var helloWorld = "Hello World";
var range = 0..4;
var hello = helloWorld[range];
Debug.Assert(hello == "Hello"); |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Instead of code like this:
We could have this:
Or how I like to write it:
Also, add new keyword 'retrun' that acts just like 'return' :)
Beta Was this translation helpful? Give feedback.
All reactions