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

Top-level statements and functions #3117

Open
MadsTorgersen opened this issue Jan 21, 2020 · 91 comments
Open

Top-level statements and functions #3117

MadsTorgersen opened this issue Jan 21, 2020 · 91 comments

Comments

@MadsTorgersen
Copy link
Contributor

MadsTorgersen commented Jan 21, 2020

Top level statements and functions

There are at least three somewhat conflicting scenarios around allowing statements and/or functions to be declared at the top level of program text.

First I'll consider each in turn, and point out how they conflict with each other. Then I'll propose an approach for C# to take.

Scenario 1: Simple programs

There's a certain amount of boilerplate surrounding even the simplest of programs, because of the need for an explicit Main method. This seems to get in the way of language learning and program clarity.

The simplest feature to address this would be to allow a sequence of statements to occur right before the namespace_member_declarations of a compilation_unit (i.e. source file).

The semantics are that if such a sequence of statements is present, the following type declaration would be emitted:

static class Program
{
    static async Task Main(string[] args)
    {
        // statements
    }
}

This would make it an error for multiple compilation units to have statements, because you'd get two classes with the same name Program. If the assembly is run, it would also be an error to have other valid entry points, such as explicit Main methods.

Scenario 2: Top-level functions

C# restricts named functions to being declared as members of types, as well as local functions. The closest you can get to a notion of "global" (or "namespace-global") functions is to put them as static members in a class C and then say using static C; in places where you want to use the functions directly without prefixing with a class name. This adds ceremony to both the declaring side and the consuming side dealing with the class C.

The simplest feature to address this is to add function declarations to namespace-member_declarations - the kind of thing you can declare globally or in a namespace.

The functions would be limited in the modifiers that apply: They cannot be abstract, virtual, override or sealed. Their accessibility, like that of top-level classes would be internal or public, with internal being the default.

There's a design decision as to which kinds of function member declarations would be allowed: methods are key, but properties, indexers, etc. could also be considered. You could even consider stateful members (fields, auto-properties), and you would essentially get global variables. User defined operators and conversions are probably completely off the table, though, as they have relationships with their enclosing type, and there wouldn't be one.

On the consuming side, the top-level members would be direct members of the namespace, just as top level types are. If the namespace is usinged, or is the global namespace, the members are directly in scope.

The implementation would be that a partial class is generated to wrap the members as static members. The class name would probably be unspeakable, and would be chosen in such a way that the same name wouldn't be used twice in the same namespace across different assemblies. If any of the top-level members are public, the class would be public, and marked in such a way that a consuming assembly would know to expose the members directly.

Scenario 3: Scripting

There is currently a "scripting dialect" of C#, where top-level statements and functions are not only allowed, but are the way the program is specified. It's similar to scenario 1, except that the statements are freely scattered among type declarations. (Namespace declarations are currently not allowed in scripting, but that may change in the future.)

The execution of a script is often performed by a "host", that is able to put specific things into scope of the script, as well as access the state of its "local" variables. This is enabled by the state being represented as instance fields of a generated class, of which the running script is an instance.

Also, scripts can be executed as individual "submissions", one after the other, with subsequent ones being within the scope of their predecessors' declarations, modulo shadowing. In this mode submissions need to be captured as objects, and cannot allow stack-only things such as ref variables. Similarly, scripts are implicitly async so that await can be used freely, and this also limits the use of certain features.

If we want to add top level statements and functions to C#, we don't want them to conflict with how those work in scripting. Rather we want to compile them in the requisite manner when necessary, but unify on the semantics of the features. This doesn't fully eliminate the scripting dialect, as we would still need to deal with the special directives and "magic commands" that it requires, but at the minimum we do need to avoid the same syntax to not mean materially different things.

Problem

The main conflict between these three scenarios is in how top-level functions are construed. Are they "local-to-the-main-program" functions (as in 1 and 3), or are they top level library declarations just like types (as in 2)?

If the former, then top-level functions can only occur as part of a top-level program. They can see the local variables of that program, but they (and the local variables themselves) aren't visible to e.g. adjacent type declarations.

If the latter, then top-level functions can occur everywhere top-level type declarations can occur. They wouldn't be able to access the state of a top-level program, unless we also interpret the "locals" of such a program as top-level "global" variables. The functions - as well as such global variables if we choose to embrace them - would be members of their namespace, visible to any code in the assembly, and, if declared public, to any other assemblies referencing it.

Proposal: Simple programs

You can squint and imagine a merged feature that serves all the scenarios. It would require a lot of design work, and some corners cut. I do not propose that. Instead I suggest that we fully embrace scenario 1, essentially fleshing out and slightly generalizing the feature sketched out for that scenario above.

The primary goal of the feature therefore is to allow C# programs without unnecessary boilerplate around them, for the sake of learners and the clarity of code. A secondary but important goal is to not introduce a fundamental conflict with scenarios 2 (which we may want to revisit in the future) and 3 (not having the meaning of top-level code differ between "program" and "script" scenarios).

It should be relatively straightforward to ensure that, while more restrictive than scenario 3, for programs that are allowed, the semantics will be approximately the same; enough so that the two don't materially conflict.

The approach more fundamentally clashes with scenario 2, and in its straightforward form it would bar us from extending the feature to embrace scenario 2 in the future. I propose that we build in additional restrictions to keep that design space open.

(If we later find that there's a need for libraries of top-level functions, we can also consider an equivalent to VB's modules, which still provide a named wrapper for static members (similar to a static class), but put the names of those members in scope implicitly when the enclosing namespace is usinged, instead of requiring an explicit using static).

Syntax

The only additional syntax is allowing a sequence of statements in a compilation unit, just before the namespace_member_declarations:

compilation_unit
    : extern_alias_directive* using_directive* global_attributes? statement* namespace_member_declaration*
    ;

In all but one compilation_unit the statements must all be local function declarations.

Example:

// File 1 - any statements
if (args.Length == 0
    || !int.TryParse(args[0], out int n)
    || n < 0) return;
Console.WriteLine(Fib(n).curr);

// File 2 - only local functions
(int curr, int prev) Fib(int i)
{
    if (i == 0) return (1, 0);
    var (curr, prev) = Fib(i - 1);
    return (curr + prev, curr);
}

Note the use of return as a top-level statement. We may find that this looks/feels wrong since it's not visibly inside a body of a member.

Semantics

If any top-level statements are present in any compilation unit of the program, the meaning is as if they were combined in the block body of a Main method of a Program class in the global namespace, as follows:

static class Program
{
    static async Task Main(string[] args)
    {
        // File 1 statements
        // File 2 local functions
        // ...
    }
}

If any one compilation unit has statements other than local function declarations, those statements occur first. The order of statement contributions (which would all be local functions) from other compilation units is undefined.

Warnings about missing await expressions are omitted.

Normally collision between multiple Main method entry points is only diagnosed if and when the program is run. However, we should consider forbidding any Main methods suitable as entry points to coexist with top-level statements. Or if we do allow them, we should not allow synchronous ones to silently take precedence over the async one generated from the top-level statements. That precedence was only reluctantly allowed over async Main methods for back compat reasons which do not apply here.

The example above would yield the following Main method declaration:

static class Program
{
    static async Task Main(string[] args)
    {
        // Statements from File 1
        if (args.Length == 0
            || !int.TryParse(args[0], out int n)
            || n < 0) return;
        Console.WriteLine(Fib(n).curr);
        
        // Local functions from File 2
        (int curr, int prev) Fib(int i)
        {
            if (i == 0) return (1, 0);
            var (curr, prev) = Fib(i - 1);
            return (curr + prev, curr);
        }
    }
}

Scope of top-level parameters, local variables and local functions

Even though the args parameter and top-level local variables and functions are "wrapped" into the generated Main method, they should still be in scope throughout the program, as if they were declared with internal accessibility in the global namespace.

This could lead to name collisions, ambiguous lookups and shadowing of imported names. If one is picked by name look-up, it should lead to an error instead of being silently bypassed.

In this way we protect our future ability to better address scenario 2, and are able to give useful diagnostics to users who mistakenly believe them to be supported.

LDM notes:

@MadsTorgersen
Copy link
Contributor Author

See relevant discussion at #2765.

@CyrusNajmabadi
Copy link
Member

CyrusNajmabadi commented Jan 21, 2020

The primary thing that bothers me here is scoping. i.e. both around 'args' as well as the scopes of variables introduced in teh statements that precede a namespace. However, it may just be an initial aversion that i coudl get over.

Given that your goal is Proposal: Simple programs, i would say that there's actually no need for scoping to extend from teh statements elsewhere. A simple program is just statements and little funcs. The moment we get to namespaces/classes/etc, we're no longer "simple" and i personally would prefer stating that they shouldn't mix.

--

another issue for me is that while this is pitched as 'simple programs' it seems to still allow the statements to coexist with namespaces/classes. First, this isn't really 'simple' to me anymore. Second, it actually opens up large cans of worms for me. For example, if i were to be able to have top-level statements that can be in scope for the rest of my program, then I absolutely would want to be able to make those top level variables readonly so they couldn't just be overwritten by the rest of my code.

I strongly like the idea of simple-programs. But I actually don't think this goes far enough. Perhaps a simple program should only be top level statements/local-funcs?

@HaloFour
Copy link
Contributor

Where do imported namespaces come in? Or do we need support for using directive within a method in order to support this? Or would the compiler take using directives and "promote" them outside of the generated class? What if multiple files want to import multiple and potentially colliding namespaces?

It's difficult to not have an immediate negative visceral reaction to this proposal. It feels like it creates yet another dialect of the language without solving for any problems or the use cases suggested. You wouldn't be able to take CSX and run it this way, not without additional syntax work. You couldn't use most of the language as you'd expect. All variables end up in some mixed global scope.

Feels like tools like LINQPad already satisfy this need and do so in a vastly superior manner.

@orthoxerox
Copy link

orthoxerox commented Jan 21, 2020

@CyrusNajmabadi I agree that simple programs should remain simple. I am not even convinced that splitting your simple program into multiple simple files is something desirable. I imagine that csc run hello.cs or dotnet run hello.cs would be the preferred mode of running them. As soon as you have multiple files you need either a csproj or some other way to refer to multiple files. The former is complicated enough that you might as well rote learn static void Main as well, while the latter leads learners away from the "proper" way of doing things.

Of course, the scripting dialect could invent its own way of including other files, but that's outside the scope of this issue.

@amdav
Copy link

amdav commented Jan 22, 2020

I agree with @MadsTorgersen proposal, that this feature should be targeting simple programs and people learning the language (and should be a shortcut for what goes inside Main()). It could be worth adding a little more detail (with examples) to the section on the scoping of local variables and functions just so everyone is clear.

@YairHalberstadt
Copy link
Contributor

YairHalberstadt commented Jan 22, 2020

I'm feeling a little bit sceptical of this proposal.

Writing a static Main function is not particularly difficult, and the tooling generates it for you anyway. In terms of benefits of top level statements I would suggest there's almost none from an actual use case perspective.

Instead I feel this is more of a marketing issue. C# looks old and stuffy because you need so many things to create an app. Python you just type something and it runs.

Marketing is important, but I don't think it's worth introducing a whole load of complexity for it. Instead I would keep this extremely simple. You can have a single file in a project with top level statements, which act exactly as if they're inside an async Main method. They are not globally scoped, and can't be referenced anywhere else. That should be enough to give beginners their python feel.

@fitdev
Copy link

fitdev commented Jan 22, 2020

For my part I really like Scenario 2. That would allow for significant time savings via less typing. And having worked with VB.NET for a number of years, I do miss VB's modules and their implicit imports.

User defined operators and conversions are probably completely off the table, though, as they have relationships with their enclosing type, and there wouldn't be one.

I would love to have globally accessible implicit and other operators I could define even for existing CLR types. So if the team can find a way to include those it would add even more value to Scenario 2.

@orthoxerox
Copy link

@YairHalberstadt I would absolutely use simple C# programs for throwaway scripts and tiny utilities. dotnet new console is fast, but it leaves behind a whole project folder with a bunch of binaries.

@YairHalberstadt
Copy link
Contributor

@orthoxerox
Would you require more than one file?

@orthoxerox
Copy link

@YairHalberstadt one file per utility/script. I've already written I don't think it's nesessary to support multi-file "simple programs".

@HaloFour
Copy link
Contributor

HaloFour commented Jan 22, 2020

If all this proposal does is take the statements in the file(s) and put that into the middle of a generated Main method why does this need to be a part of the compiler or C# spec at all? Couldn't a separate dotnet tool be shipped which does that for users? A simplified tool could be geared towards making this as easy as possible. And you could prototype this all out right now without having to touch Roslyn or the C# spec.

@orthoxerox
Copy link

@HaloFour It's a bit more complex than that, since the tool has to recognize the usings as well.

@HaloFour
Copy link
Contributor

@orthoxerox

It's a bit more complex than that, since the tool has to recognize the usings as well.

I see nothing in this proposal that claims that using directives would be supported. That would land us firmly back into dialect territory since said directives aren't permitted mid-method. But, if this proposal would need to support it, without a corresponding change to the language, then an external tool could also do so just as easily. CSX already does it.

IMO, we'd get more mileage making it easier to get/use CSX, and adding support for converting CSX scripts to a C# project.

@svick
Copy link
Contributor

svick commented Jan 22, 2020

For me, the simple programs I would want to write:

  • Are single file.

  • Are ordered usings, types, functions, statements, e.g. (artificial example):

    using System;
    
    class C
    {
        public int P { get; set; }
    }
    
    void Print(C c) => Console.WriteLine(c?.P);
    
    Print(new C { P = 0 });
    Print(null);
  • Types don't need access to local variables from statements.

This means that for me, the suggested ordering of "statements right before the namespace_member_declarations" would not be natural, I'd prefer it the other way around.

And being able to have top-level local functions in other files and being able to access top-level local variables from other files is unnecessary and probably undesirable.

On the other hand, the suggestion by @CyrusNajmabadi of having only "top level statements/local-funcs" goes too far: being able to declare types is necessary for the "simple programs" I want to write.

@CyrusNajmabadi
Copy link
Member

Very interesting point @svick . Thanks!

There's something definitely more appealing to me about that as it feels much more 'natural' in terms of scoping. i.e if i think of the 'top level locals' i declare as similar to 'method locals', then placing them after everyting else feels 'better' (since locals can't be referenced by code that is earlier than their declaration).

@orthoxerox
Copy link

@HaloFour Take a look at the grammarlet Mads posted:

compilation_unit
    : extern_alias_directive* using_directive* global_attributes? statement* namespace_member_declaration*
    ;

Usings are supported, and they must precede the statements. I actually don't mind if CSX is merged with mainline C#, I can then just treat this proposal as the first step in that direction.

@Thaina
Copy link

Thaina commented Jan 23, 2020

Would like to voice that I prefer the scenario 2 specifically

Is it true that I could assume that top level function will be internal static by default? If it is then, as for simple program purpose, just one void Main is already reduced enough from the verbose class and static

Another main reason I really support this feature is that, outermost void Main will become exactly one in the whole program, never be any conflict thereafter. It also true for any same name singleton function we want

Also I would like to repeat myself that, I wish that we could not write top level statement. Only function and property. Because, unlike class that easily make dependency chain, we cannot expect timing and order of the statement aside from void Main

@DavidArno
Copy link

Scenario 2 is also my preferred option.

But I disagree with @MadsTorgersen suggestion of:

Their accessibility, like that of top-level classes would be internal or public, with internal being the default.

private should be supported and should be the default, in my view. Each file containing its own set of free functions should end up as a differently named static class, allowing each to contain its own private functions.

@YairHalberstadt
Copy link
Contributor

private should be supported and should be the default, in my view. Each file containing its own set of free functions should end up as a differently named static class, allowing each to contain its own private functions.

I think that would be very useful to support an FP rather than class based style of programming. Each file becomes a sort of module and defines a number of private, internal, and public functions.

@MgSam
Copy link

MgSam commented Jan 23, 2020

I don't understand the use case here. Is something wrong with 'csx' scripts? Why can't 'learners' and those who want 'simple programs' just use the already-existing scripting dialect?

If the reason is "no one is using it"- that's a tooling and education problem, not a language design problem. You guys released CSX and then did close to zero promotion of it- to my knowledge, no one official has ever blogged about it or demoed it at conferences, and development on C# Interactive stopped almost as soon as it started.

@genlu
Copy link
Member

genlu commented Jan 23, 2020

I strongly like the idea of simple-programs. But I actually don't think this goes far enough. Perhaps a simple program should only be top level statements/local-funcs?

@CyrusNajmabadi I agree. IMO, having both top level statements/local-funcs and "regular" C# code coexist as proposed here can work, but allowing them to mix might be against the simple program scenario that motivated this proposal in the first place.

However, this would pretty much make it identical to a csx, right? It seems to me that making improvement to existing C# scripting would address the simple program scenario more effectively.

@iam3yal
Copy link
Contributor

iam3yal commented Jan 24, 2020

@MgSam The motivation here is to come up with a single dialect where you wouldn't have to think about the environment regardless to proficiency or task, people who just want/need to write a "simple program" and run it shouldn't use a different tool just because now they want to define a top-level function or whatever but for beginners this might be a show stopper especially for new programmers with no prior knowledge and this barrier is a language concern because there are two different dialects and two different tools for the same language.

@iam3yal
Copy link
Contributor

iam3yal commented Jan 28, 2020

@AlgorithmsAreCool With all due respect your comment makes zero sense here.

@AlgorithmsAreCool
Copy link

@eyalsk In retrospect, I agree. I've removed it.

@HaloFour
Copy link
Contributor

@RUSshy

Does it really solve that problem, though? Sure, you might get "Hello World" off the ground faster, but for anything even slightly less trivial you're going to have to jump that same hurdle.

And does that hurdle really exist, even for beginners? Odds are that a beginner is starting from a tool like Visual Studio or dotnet new which writes all of that boilerplate for you. If they're trying to write this program from the command line they've already had to vault significantly higher hurdles.

If adoption and outreach are the goals I'd suggest that there are significantly better opportunities that don't result in creating dialects of the language. And if the Tiobe index is to be trusted it doesn't appear that C# is having too many issues attracting developers. Neither do most of the other languages towards the top of that list most of which require some kind of syntactic boilerplate.

Oh, and bring back temporary solutions in Visual Studio. The removal of that feature has been infinitely more annoying to my ability to toss together a quick&dirty project than having Visual Studio automatically generate some code around the code I want to write.

@Thaina
Copy link

Thaina commented Jan 29, 2020

@HaloFour

dotnet new which writes all of that boilerplate for you

In the eye of beginner programmer, even the word namespace and class itself is already magic that require them to understand that they cannot put a logic code inside those block. They need to learn that they could only put code into the bracket of void Main

Starting with dotnet new will present them a sudden 3 layers that require understanding. This proposal can reduce to only one (or zero, if we could write a top level statement)

@Daynvheur
Copy link

Daynvheur commented Aug 5, 2020

Scripts I made or was confronted to may often fit in the 1st "Simple programs" category, but with source code split under multiple files.
Languages like AutoIT may #include <File.au3> and have these blob-added by its wrapper, BATCH may call an external command. The "more than one file per script" case doesn't seem uncommon.

@333fred 333fred moved this from 10.0 Candidate to REJECTED in Language Version Planning Sep 28, 2020
@333fred 333fred modified the milestones: 10.0 candidate, Likely Never Sep 28, 2020
@redradist
Copy link

@333fred What does mean REJECTED ?
That is all, this feature with Top-Level functions will not be developed in near future ?

@333fred
Copy link
Member

333fred commented Nov 16, 2020

That is all, this feature with Top-Level functions will not be developed in near future ?

Correct. See https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-09-28.md#top-level-functions.

@redradist
Copy link

redradist commented Nov 16, 2020

@333fred It is very disappointed ... ((((((((((((
I've started thinking that Microsoft consider community opinion ... I am very disappointed ((((((((((((((((((

@CyrusNajmabadi
Copy link
Member

I've started thinking that Microsoft consider community opinion

We did. That was part of our decision making process. But we rejected this proposal as we didn't think it was the right direction for the language.

@redradist
Copy link

@CyrusNajmabadi I think to make right decision for this feature is to create a poll and ask people will they use this feature and would not be it annoying that exist two solutions: static methods and free functions ...

@redradist
Copy link

@333fred @CyrusNajmabadi C++/Swift has both top-level functions and static methods and it is not annoying anyone:

https://docs.swift.org/swift-book/LanguageGuide/Methods.html

@HaloFour
Copy link
Contributor

@redradist

Both of those languages have had top-level functions since their inception.

@CyrusNajmabadi
Copy link
Member

CyrusNajmabadi commented Nov 16, 2020

@CyrusNajmabadi I think to make right decision for this feature is to create a poll

The language direction is not decided by polls. It has a design group that has total control over the design process here.

C++/Swift has both top-level functions and static methods and it is not annoying anyone

What C++ and/or Swift do isn't part of our decision making process for C#.

and ask people will they use this feature and would not be it annoying that exist two solutions: static methods and free functions

'annoying' was not part of the decision making process. We genuinely do not believe this is a good feature to add to C# at this point in the lifecycle of the language.

@redradist
Copy link

@CyrusNajmabadi I think to make right decision for this feature is to create a poll

The language direction is not decided by polls. It has a design group that has total control over the design process here.

C++/Swift has both top-level functions and static methods and it is not annoying anyone

What C++ and/or Swift do isn't part of our decision making process for C#.

and ask people will they use this feature and would not be it annoying that exist two solutions: static methods and free functions

'annoying' was not part of the decision making process. We genuinely do not believe this is a good feature to add to C# at this point in the lifecycle of the language.

@CyrusNajmabadi
It should not be about believing or feeling ... It is not technical terms, there is should be Mind Map - what this feature will provide and allow to achieve ...

@CyrusNajmabadi
Copy link
Member

CyrusNajmabadi commented Nov 16, 2020

It should not be about believing or feeling

It is entirely about that. The language design group chooses which features are added to the language based on their personal beliefs and feelings.

It is not technical terms

The features we decide on the for the language are not chosen based solely on their technical terms.

what this feature will provide and allow to achieve

Yes, that feeds into our decision making. We are aware of what would be enabled by this, and we made a determination if this would be an overall positive for the language. We decided it would not be, so we rejected the feature.

@CyrusNajmabadi
Copy link
Member

CyrusNajmabadi commented Nov 16, 2020

@redradist This tangent doesn't seem to be going anywhere. If you would like to discuss this further, we have several conducive avenues for that. Please consider gitter.im/dotnet/csharplang or discord.gg/csharp (#roslyn channel).

@CyrusNajmabadi
Copy link
Member

@RUSshy as above: if you'd like to discuss this further you can do so at gitter.im/dotnet/csharplang or discord.gg/csharp (#roslyn channel).

This language feature has already been decided upon. The disappointment of people was factored into the decision making process here. We assessed the pros and cons of this and determined this was not something we felt was valuable enough to make it int the language.

@Thaina
Copy link

Thaina commented Nov 17, 2020

Reading LDM and then I still don't think it was the right direction of decision. I don't think we need to care about BCL at all

The first thing we would do with top level function is naked Main. Everyone will start using that. And then every function for using with Main until we really need to use class or struct. At least it would be shared in the same assembly or namespace. It would never be minimal usage at all because everyone will start using it from the start of the project. It make prototyping faster

If there is any concern about collision I think it would be the same as introducing new function in static class then use static using. If that was not the concern this also should be none

As I was proposing. We can treat this feature as just automatic assuming default namespace and default class name of the assembly and just transpile at the compile time

Actually, this feature real usage are most likely internal function so it just add convenience to development time. But we are less likely expose it, we would always have using and using static for that. So it should not concern about BCL at all

I think this would be another wrong decision as generic from C# 1. You underestimate our real usage

@CyrusNajmabadi
Copy link
Member

CyrusNajmabadi commented Nov 17, 2020

I still don't think it was the right direction of decision.

Ok 👍

You underestimate our real usage

Perhaps. But that's life. We have to use our best judgement and make a call. That call was made here. I get that you don't like the decision we made. But nothing had changed that would cause us to reassess that.

--

And, as above: if you'd like to discuss this further you can do so at gitter.im/dotnet/csharplang or discord.gg/csharp (#roslyn channel).

@CyrusNajmabadi
Copy link
Member

Any further discussion on this topic will need to go to gitter.im/dotnet/csharplang or discord.gg/csharp (#roslyn channel). Thank you.

@Thaina

This comment has been minimized.

@CyrusNajmabadi
Copy link
Member

@Thaina Any further discussion on this topic will need to go to gitter.im/dotnet/csharplang or discord.gg/csharp (#roslyn channel). Thank you.

@Thaina

This comment has been minimized.

@spydacarnage

This comment has been minimized.

@Thaina

This comment has been minimized.

@spydacarnage

This comment has been minimized.

@gulshan

This comment has been minimized.

@CyrusNajmabadi
Copy link
Member

More measurable and mechanical the decision making process is,

The decision making process is not done in a measured or mechanical fashion.

This entire meta discussion on how people want the language designed is not useful here. The decision has been made on this issue. The reasoning has been explained.

If you want to start a different discussion on how the language is designed, feel free. However, it will remain off topic on this issue.

@dotnet dotnet locked as too heated and limited conversation to collaborators Nov 17, 2020
@333fred 333fred removed this from REJECTED in Language Version Planning Feb 6, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests