Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: Introduce let as keyword for lazy constants #7453

Closed
v-andrew opened this issue Dec 12, 2015 · 21 comments
Closed

Proposal: Introduce let as keyword for lazy constants #7453

v-andrew opened this issue Dec 12, 2015 · 21 comments

Comments

@v-andrew
Copy link

C# already uses let clause in LINQ expressions.

Please extend use of let and make it to a general purpose keyword which declares lazy constants.
It looks organic and I see no confusing side effects.
Here are examples of 'new' syntax:

let x = "The quick brown fox jumps over the lazy dog";

the same as const x

let y = x.Substring(0, 10);

const y declared but not evaluated until it is used in expression.
As it is considered to be a constant and has no side effects, compiler could optimize use of y.
for example, when user takes length of y compiler can substitute it with 10

@v-andrew v-andrew changed the title Proposal: Introduce **let** as keyword for lazy constants Proposal: Introduce let as keyword for lazy constants Dec 12, 2015
@alrz
Copy link
Contributor

alrz commented Dec 12, 2015

There is no such thing as lazy evaluation in CLR. However, you can use Lazy<T> class for this purpose.

var y = new Lazy<string>(() => x.Substring(0, 10));

And let is being used for decomposition (#6400).

@HaloFour
Copy link

Furthermore, as a part of that decomposition spec, let is proposed as shorthand for a readonly local variable using the exact syntax as stated above: let y = x.Substring(0, 10);

@alrz
Copy link
Contributor

alrz commented Dec 12, 2015

Although, there is a similar feature in F# as lazy keyword but it makes all variable captures implicit, and I think it wouldn't be preferrable because the same issue with lambda expressions is being addressed by #117.

@v-andrew
Copy link
Author

I think 'let' should be a compiler feature rather than CLR, so compiler could optimize let expression.

@v-andrew
Copy link
Author

#6400 and #117 cover most of my suggestion.

However I suggest to make next step and have let as a first class citizen and make it work where const doesn't fit.

  for(var i=0; i< 10; i++)
  {
      const int x = i; // Error CS0133  The expression being assigned to 'x' must be constant
      // will be
      let x = i;
      ...
  }

When we look at the application code, there are quite a few places, where var could be replaced with thread safe immutable lazy let and have compile time optimization as side effect.

Ultimately, it should lead to a for loop with let instead of var

  for(let i=0; i< 10; i++) {...}
// or
  foreach(let i in 0..10) {...}

@HaloFour
Copy link

However I suggest to make next step and have let as a first class citizen and make it work where const doesn't fit.

This is a side-effect of #6400, the destructured values would be immutable but can be the result of any expression. They would be evaluated immediately, though, which is necessary as the expression could have more side-effects than simply resulting in a value and it would be very unexpected if those side-effects did not occur at the point that the expression occurs lexically.

Also, iteration variables are already immutable and thread-safe (per C# 5.0) so there is no need to extend foreach to support let. Changing for to support let doesn't make any sense as the iteration variable must be mutable.

@v-andrew
Copy link
Author

Changing for to support let will make loop variable immutable within a scope, so behaviors will be more straightforward and could be defined by user and optimized by compiler.

I would change foreach syntax to reflect that loop iterates over constant, not variable.

@alrz
Copy link
Contributor

alrz commented Dec 25, 2015

@v-andrew can you give an example for for with an immutable variable?

@HaloFour
Copy link

@v-andrew The iterator variable must be mutable since the for loop must mutate it. You could argue that the variable would be immutable except for within the initializer, condition or iterator statements of the for loop but I don't think I am aware of any language that functions like that.

In Swift, for (let x = 0; x < 10; x++) { } is not legal.

Why should the syntax of foreach change and what should it change to? If foreach (let x in y) is to be permitted, what would it differ over foreach (var x in y)? If in the latter x would become mutable that would represent a pretty big change to the language, even if it wouldn't be a breaking change.

@v-andrew
Copy link
Author

@alrz

  for(let i=0; i< 10; i++)
  {
      i++; // Error
  }

I'm not sure that it looks good as i++ implies changes in i, so we could move to

  for(let i=0; i< 10; i + 1)
  {
      i++; // Error
  }

Life cycle of i is limited to for body and changing loop variable is never a good idea so we just declare it explicitly.
This is a hint to compiler that i is not a variable so code could be optimized.

@v-andrew
Copy link
Author

@HaloFour foreach (let x in y) should replace foreach (var x in y) and foreach (var x in y) declared obsolete

@alrz
Copy link
Contributor

alrz commented Dec 25, 2015

wa.. wait a minute. so, i in every iteration never changes? becasue that is what let implies.

@HaloFour
Copy link

The i++ or i += 1 is important to for, the iteration variable is being mutated. Even if new syntax would result in i being immutable within the block, i is still being mutated. Limiting the nature of the statement or how the iterator statement works makes no sense.

foreach (var x in y) isn't going anywhere so it makes little sense to introduce new syntax which does absolutely nothing but duplicate the behavior of existing syntax.

@v-andrew
Copy link
Author

@alrz Yes, i never changes within for body after it is initialized in for(let i=0; i< 10; i + 1)

@v-andrew
Copy link
Author

@HaloFour I do not suggest to remove for(var i=0; i< 10; i++) or other forms of for loop.

@paulomorgado
Copy link

@v-andrew, are you aware that you can initialize more than one variable in the for statement, use whatever you want to on the condition and have multiple statements in the iteration?

int k = 1;
int l = 0;
for (int i = 0, j = 0; l < 10; i++, j++, k *= 2)
{
    Console.WriteLine($"i = {i}, j = {j}, k = {k}, l = {l++}");
}

@Thaina
Copy link

Thaina commented Jan 13, 2016

Why the heck we need new keyword just for lazy constant???

Why we don't just reuse const instead

I mean instead of

const var Constant = 5;

We can just

const Constant = 5;

And let const be known as shorthand const var. Problem solve

Please don't add any new keyword so casually

@v-andrew
Copy link
Author

@paulomorgado Yes, I know it, however I see no relations to my proposal

@v-andrew
Copy link
Author

@Thaina "Why the heck we need new keyword just for lazy constant???"
This is not just for lasy constant.
It is for local constants and lazy constants.

"Please don't add any new keyword so casually"
let is already C# keyword and mentioned it above.

@Thaina
Copy link

Thaina commented Jan 15, 2016

@v-andrew It is keyword only inside query expression

Same go for value is keyword only in set {}

We should not bring keyword from lesser scope out of it scope. That's why I prefer const because it is outer scope than function

@gafter
Copy link
Member

gafter commented Mar 20, 2017

We are now taking language feature discussion on https://github.com/dotnet/csharplang for C# specific issues, https://github.com/dotnet/vblang for VB-specific features, and https://github.com/dotnet/csharplang for features that affect both languages.

@gafter gafter closed this as completed Mar 20, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants