dotnet / sdk

Core functionality needed to create .NET Core projects, that is shared between Visual Studio and CLI
https://dot.net/core
MIT License
2.74k stars 1.07k forks source link

Flag option for dotnet new to toggle globals in templates #19400

Open lukemcdo opened 3 years ago

lukemcdo commented 3 years ago

The C# Language team is insisting on including global using statements, and multiple teams appear to want to use this in their templates, from my understanding.

This is an unappealing option to me -- I would like to not have to deal with the mental load of global using statements and their resulting complications.

I would like an option, when using dotnet new to create a new C# project from a template, to be able to add a flag to the dotnet new command that substitutes a using statement at the top of each file in the template in place of a global using statement. This will add convenience to using dotnet templates.

dotnet-issue-labeler[bot] commented 3 years ago

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

sfoslund commented 3 years ago

@marcpopMSFT how are we triaging global usings feedback? Should I tag someone or do we have a label or anything?

marcpopMSFT commented 3 years ago

For now, assign all implicit usings feedback to @JunTaoLuo. I also went ahead and created a label as there are enough of them that we'll want to better be able to track them.

JunTaoLuo commented 3 years ago

This sounds like a templates issue, so I've tagged @DamianEdwards and @KathleenDollard for reference.

DamianEdwards commented 3 years ago

Thanks for the feedback. To clarify, the suggestion is to add an option to all the project templates that when set would disable implicit usings in the project file (via <DisableImplicitNamespaceImports>false</DisableImplicitNamespaceImports>) and list all required usings in the individual .cs files instead, e.g.

> dotnet new console --use-implicit-namespace-imports false

Thoughts:

Additionally I assume we'd want the option to be exposed in the Visual Studio UI when creating a new project too but that's possibly a separate (but related) decision.

@KathleenDollard interested in your thoughts. Obviously each template option adds complexity and I'm conscious of the potential for adding an option for one feature to become prior-art for arguing options for all new features (e.g. file-scoped namespace declarations, nullable reference types, etc.) which is something so far we've wanted to avoid without substantial feedback that it's desired.

lukemcdo commented 3 years ago

What I'd say in response to the potential proliferation of template options is that this is a language feature that affects future files created within the project, not just current files. The other items you listed don't have this characteristic to the same degree, in my opinion.

I prefer them disabled by default in the short run (not sure how long it is) because existing documentation won't match the template otherwise. It also gives a chance for users who like the feature to indicate what set of includes should be the default, rather than just pushing them to everyone. I could understand enabling them by default for new installations in the .NET SDK 7 timeframe or so.

DamianEdwards commented 3 years ago

We've decided to not add this option (or any others related to the use of new language features) to the templates in .NET 6. We can reassess this decision during .NET 7. Folks can still create new projects targeting .NET 5 (via the --framework option) and then retarget them to .NET 6 if they don't want the .NET 6 template content.

lukemcdo commented 3 years ago

This is frustrating when you consider that .NET 5 is deprecated 6 months after the release of .NET 6, and .NET 7 isn't expected until past 6 months after the launch of .NET 6. That leaves a notable gap in support for the pattern developers have been using for decades.

There's also expected to be an uptick in templates that simply won't be compatible with .NET 5, and it sounds like the workaround for those projects will be hand editing, which is even more disappointing.

DamianEdwards commented 3 years ago

@lukemcdo I'm not quite following where your concern lies with regards to "gap in support for the pattern developers have been using for decades". To be clear, placing usings in each file is of course still supported by the compiler. Do you simply mean support for creating a new project that targets .NET 6 but doesn't use the new features such as implicit usings and nullable reference types? If that's the case, as I said above you could create new projects targeting earlier framework versions using the latest SDK then retarget them to .NET 6 to get the .NET 5-era template. Alternatively the community could provide a template package that uses the .NET 6 template content but without the use of implicit usings, file-scoped namespaces, nullable reference types, etc.

lukemcdo commented 3 years ago

My primary concern with default implicit includes is their consistency with existing documentation and templates for new/returning users to .NET.

A template that chooses to use global includes will, out of the box, produce quite different-looking code to what that same user just produced with .NET 5. This is fine for users who can figure out what’s going on and adjust their mental models in a few minutes, but not great for someone in the middle of learning C#.

Worth noting – it is common for new users to make a mistake in a project they’ve started, feel like they can’t fix it, and start over with a new project generated from a template. I watched this pretty often with students I’ve helped. If they’ve upgraded to .NET 6, that will go poorly. This extends, potentially, to entire curriculum built around .NET. It will certainly cause confusion for my local community college when they upgrade their material.

While I understand that ultimately it’s the template owner’s choice, I don’t see the workaround you described as proper support.

Considering other features you mentioned that could be considered jarring, I see this feature as different from the other features you listed because it’s a subtraction. Most people entering programming-centric courses expect there to be new additions to tools. Global includes don’t fit that mental model.

I’m also concerned because missing .NET 6 would probably mean that VS 2022 will not support this feature ever, since it wouldn’t be available in the LTS that will correspond to most of its lifecycle.

DamianEdwards commented 3 years ago

We've made large, impactful changes to project templates many times during the .NET Core lifecycle, especially the web templates, which have the same potential issues as you point out, and each time we've attempted to mitigate those issues through documentation and communication. Ultimately, features come and go, idioms change, yesterday's boilerplate is today's default, and I don't see that trend changing. We've made a conscious decision to have new projects use the new features and at the same time are very wary of proliferating choice by adding template variants or numerous switches to control the output related to versions.

All that said, we're open to feedback and will reconsider this request based on the feedback we receive during the rest of the .NET 6 prerelease cycle.

jeromelaban commented 3 years ago

I've just experienced that new feature default, and it's not particularly existing-project-friendly. I seems though that the .NET team now says it'll be disabled by default.

Even when turned on, I'd find useful to have the generated file contain a documentation link on how to disable it, since it's one of the first that shows up (when building with LangVersion below 10.0). When building starting from C# 10, then errors will be raised outside the globals generated file, making it more difficult to find the reasons for ambiguities, though.

doomchild commented 10 months ago

I apologize for replying to such an old thread, but as it's still open, I thought it was better than opening a duplicate issue.

Is there any chance of this being fixed? My team doesn't use implicit usings, and not having the ability to turn them off at the template level makes putting together a tool to quickly scaffold new repositories more complicated. I understand the argument of not wanting to have a million switches, but the templates are the place where enabling or disabling a feature like this makes sense.

DamianEdwards commented 10 months ago

@CyrusNajmabadi thoughts on adding a code-fixer/refactoring to handle toggling implicit usings on and off?

CyrusNajmabadi commented 10 months ago

@DamianEdwards we'd have no problem with that. Basically though, we'd recommend that .net (probably SDK?) own this, as implicit-usings are a thing entirely outside of Roslyn or the language.

So .net would make a refactoring to disable this, making the right change to the project for as appropriate.

doomchild commented 10 months ago

I was referring to it being a part of the template process (at the dotnet new stage). Once a project is open, going into the csproj file and turning it off isn't a huge deal. But if I'm putting together a little generator to scaffold our repos into the patterns we use, it's frustrating to have to have steps after "run the generator in the repository". The immediate response is "why can't the generator do that?"

DamianEdwards commented 10 months ago

@doomchild I appreciate that, but my concerns are primarily about the cost of implementing and maintaining such a option in all the templates shipped with .NET. The templates are owned by different teams and in many cases don't share source/build infrastructure so adding global options that impact nearly every file in the template like this are very expensive. Something like a code-fixer that can be executed by the IDE or via something like dotnet format is more attractive as it's useful in more scenarios and can be authored once without side effects to other assets.

baronfel commented 10 months ago

+1 to Damien's thoughts here - VS does a post-generation formatting pass as part of its template flow, and the in-design templating experience for C#/Dev Kit could do the same.

doomchild commented 10 months ago

/sigh

Okay. I'll just wire up a little bit of XML parsing to rewrite the csproj file to turn it off. It's gross, but I guess it's really the only way to keep our existing patterns unchanged.

DamianEdwards commented 10 months ago

@baronfel we should consider adding a post-creation task to execute dotnet format to the template engine too (although now I've typed this out it sounds eerily familiar, perhaps we're already tracking that somewhere...)

baronfel commented 10 months ago

@DamianEdwards yeah, the tracking issue is https://github.com/dotnet/templating/issues/5505

doomchild commented 10 months ago

Is there an .editorconfig setting to require implicit usings to be disabled (I don't see an applicable rule in the docs)? Because if there is, I can have my generator call dotnet format. I didn't actually know about dotnet format, so if it's possible to use that, I'd much prefer it.

DamianEdwards commented 10 months ago

Not that I'm aware of. @baronfel is it possible to add a rule for something that's ultimately MSBuild-based? I don't know much about the workings of .editorconfig.

pardahlman commented 1 month ago

It is surprising to me that there is no way to disallow the usage of global usings considering the impact it has on the code base. A setting in csproj would be desirable (similar to <ImplicitUsings>disable</ImplicitUsings>).