Added: C# Design Notes for Jan 2018 #1403
Replies: 21 comments
-
Unblocking Are there old notes around that explain why |
Beta Was this translation helpful? Give feedback.
-
For range: It reads like you think negative index will not be used for indexing. But it is common for |
Beta Was this translation helpful? Give feedback.
-
Was there any specific reason why you didn't discuss supporting both right-inclusive and right-exclusive ranges? |
Beta Was this translation helpful? Give feedback.
-
Wouldn't unblocking where T : struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T> Which accepts every numeric type, but still allows custom structs that implement all those interfaces. |
Beta Was this translation helpful? Give feedback.
-
@Logerfo No, |
Beta Was this translation helpful? Give feedback.
-
I prefer inclusive ranges for the range pattern, while I like exclusive ranges for the indexing purpose. |
Beta Was this translation helpful? Give feedback.
-
NOOOOOOOOOOOOOOOOO!! - right-exclusive ranges are bad (IMO).
Think about those poor devs switching from/to F#. Do you really want to imitate Python instead of our brother F#? And think about the mathematicians -- Our ancestors..... The ones, who laid the foundations of information technology and programming ..... Dear LDT, I think that right-exclusive ranges are a bad 'default' for ranges. Make them inclusive. Think about an other syntax for exclusiveness, e.g. And most importantly - think about readability! For us mathematicians |
Beta Was this translation helpful? Give feedback.
-
those that come from F# would be pretty damn shocked once they see the syntax for |
Beta Was this translation helpful? Give feedback.
-
I think both syntaxes have their drawbacks, and both should ultimately be provided. No one exclusively writes Take some simple F# code: module Test
let ForInclusive(length:int32) =
for i = 0 to length do System.Console.WriteLine(i)
let ForExclusive(length:int32) =
for i = 0 to (length - 1) do System.Console.WriteLine(i) This gets compiled down to (essentially): public static void ForInclusive(int length)
{
int i = 0;
int end = length;
if (end >= i)
{
do
{
Console.WriteLine(i);
i++;
}
while (i != (end + 1));
}
}
public static void ForExclusive(int length)
{
int i = 0;
int end = (length - 1);
if (end >= i)
{
do
{
Console.WriteLine(i);
i++;
}
while (i != (end + 1));
}
} F# is doing all of this to protect against overflow bugs such as:
|
Beta Was this translation helpful? Give feedback.
-
To add some argument for exclusive: E.g. it is common to use the length of the range, and with exclusive range, that's It is counter intuitive at start, but when get used to, it feels like the one true (tm) way. Exclusive is also the typical ways for indexing/slicing in C and derived languages, even in JavaScript. Some level of consistency is really beneficial as C# developers often also need to code some JavaScript, etc. |
Beta Was this translation helpful? Give feedback.
-
Please do not use profanity in this repository ;) |
Beta Was this translation helpful? Give feedback.
-
@Unknown6656 But what if I really like **********? 😓 |
Beta Was this translation helpful? Give feedback.
-
Except that with query clauses, there is no syntactical lambdas, and therefore, one would expect scoping not be defined around those. I think one of the advantages of using linq is exactly that. The compiler should handle scoping etc of the variables introduced in a query clause and do not depend on the underlying lowered form. |
Beta Was this translation helpful? Give feedback.
-
I think this can address #1130. I propose we define retunability wrt the last value assigned (instead of the first value assigned) var local = 42;
ref int r1;
r1 = ref local;
return ref r1; // ERROR
r1 = ref field;
return ref r1; // OK Span<byte> s;
s = stackalloc byte[10];
return s; // ERROR
s = new byte[10];
return s; // OK |
Beta Was this translation helpful? Give feedback.
-
When the code is not straight-line, which execution path should we use to decide which is "last"? |
Beta Was this translation helpful? Give feedback.
-
I can't personally remember hte last time i used an inclusive range. On the other hand, i use exclusive ranges all the time (in C#, TS and Go). Now, that said, it might be because so much of the compiler and IDE space fits exclusive-end-range math so well. We've already had Spans in that space with the VS.Span construct and the Roslyn.TextSpan construct. So maybe it's just utter familiarity there. However, it seems to just make the most sense with so much stuff i use spans for. |
Beta Was this translation helpful? Give feedback.
-
Could be the most restrictive lifetime from all values that flows out of their individual blocks, making it identical to how we infer lifetimes from ternary operands. Span<int> M1(bool b) {
Span<int> s;
if (b) s = new int[10];
else s = stackalloc int[10]; // error here, with default lifetime (external)
return s; // error here, with inferred lifetime (current)
}
Span<int> M2(bool b) {
Span<int> s = b ? new int[10] : stackalloc int[10];
return s; // error here, lifetime is inferred from intersection of both operands
} |
Beta Was this translation helpful? Give feedback.
-
I'm not sure this warrants a new data-flow pass in the compiler. |
Beta Was this translation helpful? Give feedback.
-
Note. The more i read this, the more i like it. Having a delimited form also gives us flexibility for other things. For example, it gives us a simple place to put things like the stepping value (if we want to support that). |
Beta Was this translation helpful? Give feedback.
-
I too think that there should be syntax for both exclusive and inclusive ranges. There are no disadvantages to having 2 range operators instead of one and the feature will be more flexible that way. It is, of course, on the design committee to choose the correct syntax, but I think there is enough inspiration in languages such as Swift ('..<' for exclusive, '...' for inclusive; similar in Nim, but with one less dot). Having inclusive ranges would also help programmers coming from F# and it would allow for specifying a range of enum values up to the end value without having to use any special syntax such as 'a..'. |
Beta Was this translation helpful? Give feedback.
-
FWIW, this is how Rust handle lifetime mismatch: The lifetime region of a local is determined by usages of itself. not the value that is assigned to it (the exact opposite of status quo in C#), for instance, // ¶m can escape
// &local can't
// 'ret' is not returned, so it has a local lifetime
fn f1(param: &i32) {
let local = 5;
let ret: &i32;
let b = true;
if b {
ret = &local; // OK
} else {
ret = ¶m; // OK
}
let a = &ret;
}
// 'ret' is returned, so it has an external lifetime
fn f2(param: &i32) -> &i32 {
let local = 5;
let ret: &i32;
let b = true;
if b {
ret = &local; // ERROR: local doesn't live long enough
} else {
ret = ¶m; // still OK
}
let a = &ret;
return &a;
} |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Many of these topics have evolved since these notes - the raw notes are available, but have yet to be cleaned up.
C# Language Design Notes for Jan 3, 2018
C# Language Design Notes for Jan 10, 2018
C# Language Design Notes for Jan 18, 2018
We discussed the range operator in C# and the underlying types for it.
C# Language Design Notes for Jan 22, 2018
We continued to discuss the range operator in C# and the underlying types for it.
C# Language Design Notes for Jan 24, 2018
Beta Was this translation helpful? Give feedback.
All reactions