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: File scoped namespaces #137

Open
Tracked by #829
bomzj opened this issue Feb 17, 2017 · 182 comments
Open
Tracked by #829

Proposal: File scoped namespaces #137

bomzj opened this issue Feb 17, 2017 · 182 comments
Assignees
Labels
Feature Request Implemented Needs ECMA Spec This feature has been implemented in C#, but still needs to be merged into the ECMA specification Proposal champion
Milestone

Comments

@bomzj
Copy link

bomzj commented Feb 17, 2017

Spec: https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/file-scoped-namespaces.md

How it looks now:

using System;

namespace Company.Project
{
    public class Product
    {        
        ...
    }
}

Why do we need to nest our class definition in namespace ? Why not to remove extra nesting ?
Isn't that better ?

namespace Company.Project
using System;

public class Product
{ 
    ...
}

LDM history:

@scottdorman
Copy link
Contributor

Well, one reason is that namespaces can be nested. thereby creating additional scopes. For example, your code

using System;

namespace Company.Project
{
    public class Product
    {        
        ...
    }
}

could also be written as

using System;

namespace Company
{
    namespace Project
    {
        public class Product
        {
        }
    }
}

In both cases the full type name, including the namespace, becomes Company.Project.Product.

Also, using directives can be either outside the namespace, as in your example, or inside the namespace, which changes the scoping of that using directive.

@bondsbw
Copy link

bondsbw commented Feb 17, 2017

Assuming the proposal does not remove the ability to nest namespaces (which would break all existing C# code), this could improve indentation for the vast majority of code.

#114 has similar goals.

@scottdorman
Copy link
Contributor

@bondsbw So you're saying that if this proposal were implemented we'd have 3 different ways to write the same scoped namespace?

using System;

namespace Company.Project
{
    public class Product
    {        
        ...
    }
}

or

using System;

namespace Company
{
    namespace Project
    {
        public class Product
        {
        }
    }
}

or

namespace Company.Project
using System;

public class Product
{ 
    ...
}

Would this new variation of the namespace directive support nesting, and if so, how? Would this be an implicit scope such that when I encounter the next namespace directive in the file it creates a nested namespace? That wouldn't work because I can have multiple top-level namespaces in a single file (never mind the question of whether or not that's a good idea, it's possible today and I've seen code that uses that ability, which would then break).

For example, if I wrote

namespace Company
using System;

namespace Project
public class Product
{ 
    ...
}

Does this compile Product to be Company.Project.Product or Project.Product?

I also noticed that the using directive is in a different spot in the original examples. In the first (what we have today in C#) it's outside the namespace. In the proposed code, it would be scoped to be inside the namespace (based on it's placement after the namespace directive). So, the original proposed code

namespace Company.Project
using System;

public class Product
{ 
    ...
}

would be equivalent to

namespace Company.Project
{
   using System;

   public class Product
   {  
       ...
   }
}

@bomzj
Copy link
Author

bomzj commented Feb 17, 2017

Weird idea of using multiple namespaces in one file which should define one entity (class). I don't remember any sample where I need to have several namespaces in one file or nesting them which produces mass of indentation as result hard to read such code.

@scottdorman
Copy link
Contributor

@bomzj I never said that multiple top-level namespaces in one file was a good idea, only that we can do it now and I've seen code files that take advantage of that. Having multiple nested namespaces in one file is also something we can do now and has completely unambiguous nesting semantics.

@bondsbw
Copy link

bondsbw commented Feb 17, 2017

@bondsbw So you're saying that if this proposal were implemented we'd have 3 different ways to write the same scoped namespace?

Yes. Proposals to break backward compatibility are DOA except in the most minor cases. It would be a huge break to remove the block syntax.

@bbarry
Copy link
Contributor

bbarry commented Feb 17, 2017

My vote would be: allow a file to allow up to 1 file level namespace directive per file and that it must come before any container namespace directives or type declarations.

Differentiate between a "file level namespace directive" and a "container namespace directive" by the fact that a file level one would not have a body and must have a semi:

namespace_declaration
    : file_namespace_declaration
    | container_namespace_declaration
    ;

file_namespace_declaration
    : 'namespace' qualified_identifier ';'
    ;

container_namespace_declaration
    : 'namespace' qualified_identifier namespace_body ';'?
    ;

Such a namespace directive would act as if it was a container namespace containing the rest of the file.

@scottdorman
Copy link
Contributor

@bondsbw Yes, proposals which break back compatibly are DOA. I still don't see how this change provides any major benefit other than not having a level of indenting, which is fairly inconsequential.

@bbarry So you're saying that we would have a new namespace <identifier>; directive that would have to be at the top of the file? So, in the example we've been using here, namespace Company.Product; would have to be the first line and I can only have one of them? This would prevent me from defining more than one top-level namespace per file and also prevent me from having using directives appear outside the namespace declaration.

@bbarry
Copy link
Contributor

bbarry commented Feb 17, 2017

No you could have using directives both above and below a file namespace directive. But you cannot have multiple file namespace directives and if you have 1, you cannot have container namespace directives or type declarations before the file namespace directive. using directives before the file namespace directive would be treated as outside and ones after, inside.

in examples:

ex1: (valid C# today)

using System;
namespace Company.Project
{
    using System.Collections;
    public class Product { }
}

or

ex2: (valid C# today)

using System;
namespace Company
{
    using System.Collections;
    namespace Project
    {
        public class Product { }
    }
}

or

ex3: (proposed, equal semantics to ex1)

using System;
namespace Company.Project;
using System.Collections;
public class Product { }

or

ex3: (proposed, equal semantics to ex2)

using System;
namespace Company;
using System.Collections;
namespace Project
{
    public class Product { }
}

but not:

ex5 (admittedly an arbitrary example, but the rational would be that if you are using both a container namespace and a file namespace it is because you have more than one container in your file or you require the semantics of ex2):

using System;
namespace Company;
namespace Project;
using System.Collections;
public class Product { }

and not:

ex6 (again arbitrary; here I am explicitly denying this as in scope in this proposal to consider it potentially for the future):

using System;
namespace Company 
{
    namespace Project;
    using System.Collections;
    public class Product { }
}

and not:

ex7 (avoiding a pit of failure due to overly complex files):

using System;
namespace Whatever {};
namespace Company.Project;
using System.Collections;
public class Product { }

and not:

ex8 (again avoiding complexity):

using System;
delegate void MyFunc(string s); //or any other type decl
namespace Company.Project;
using System.Collections;
public class Product { }

@jnm2
Copy link
Contributor

jnm2 commented Feb 17, 2017

I was hoping this would make it over from /roslyn.

Putting the namespace in the class name appeals to me the most since I have never, ever defined more than one namespace per file. It would be great if that worked for partial classes too:

// File MyClass.cs
partial class MyNamespace.MyClass { }
// File MyClass.NestedType.cs
class MyNamespace.MyClass.NestedType { }

However, the namespace with an implied scope extending to the end of the parent scope would be an acceptable compromise. There is no possible ambiguity.

@scottdorman About ambiguity: just like the using proposal, the scope is not ambiguous. It always extends to the very end of the parent scope, the same behavior that the scope of a declared variable would have in that position. I don't care for the using syntax, but the same principle applied to namespace would be a huge benefit because four nines of the time people have a single namespace per file.

@scottdorman
Copy link
Contributor

I agree, the vast majority of the time we only have one namespace per file and only have one class per file. However, that's not always the case and it's certainly not enforced by the compiler and/or IDE. (I've worked in languages that enforced this, and it got to be a real pain. That's not to say there may be good ways to actually do this where it doesn't get in your way more often than not, though.)

The ambiguity about what the scope actually is comes about if multiple namespace x; directives are allowed in a single file. Does the outermost directive define a scope such that the next directive is nested? If so, that is more limiting than what we have now where I can define the scopes however I want/need.

I'm not a big fan of having the namespace be part of the class name at all. First, it requires changing what constitutes a valid class identifier, but more importantly I think it introduces a lot of redundancy as far as namespaces go. Would the using directives just appear before the class declaration? How would you scope them to be contained within the namespace?

Given @bbarry's earlier examples, I still find this

using System;
namespace Company
{
    using System.Collections;
    namespace Project
    {
        public class Product { }
    }
}

to be considerably more readable than

using System;
namespace Company;
using System.Collections;
namespace Project
{
    public class Product { }
}

Especially since, at least to me, all this is really doing is letting me skip two curly braces and some indenting, I don't see the benefits. (I have the same issue, among others, with the implicitly scoped using statements as well.) I'd much rather see language features that make the language easier to read (which this doesn't, in my opinion) and reduce my ability to write code that can have unexpected/unintended side-effects than ones that make it harder to read and introduce more places for ambiguity.

@jnm2
Copy link
Contributor

jnm2 commented Feb 17, 2017

The ambiguity about what the scope actually is comes about if multiple namespace x; directives are allowed in a single file.

I don't see an ambiguity. Same with the using thing:

using (a);
// Invisible { for a

// Still using a even though no indent

using (b);
// Invisible { for b

// Still using a and b even though no indent

// Invisible } for b
// Invisible } for a
namespace a;
// Invisible { for a

// Namespace here is "a" even though no indent

namespace b;
// Invisible { for b

// Namespace here is "a.b" even though no indent

// Invisible } for b
// Invisible } for a

I agree with you that this would not be as flexible for multi-namespace files, but

  1. the same goes for the using and there is an easy workaround if you need to be more specific about scope: go back to using { and } for that file
  2. We're honestly talking 0.01% of the time. Let's optimize for the common scenarios that affect everyone every day. The same goes for multiple levels of using nesting. If it's too complex, choose not to do it and use { and } instead. But don't punish the almost universal case of single using block, single namespace.

@bomzj
Copy link
Author

bomzj commented Feb 19, 2017

Why not to use 2 types of declaring namespace ? The old approach with nesting where multiple namespaces are need and new one as single line for vast majority.
One more loud thought whether it's possible to eliminate namespace keyword from *.cs files at all and map fully qualified class name to physical folder structure instead like java does ?

@bondsbw
Copy link

bondsbw commented Feb 19, 2017

@bomzj I suggest opening up a separate proposal for the folder structure idea.

@DavidArno
Copy link

@scottdorman,

using System;
namespace Company;
using System.Collections;
namespace Project
{
    public class Product { }
}

wouldn't (or at least, shouldn't) be allowed under this proposal. By having two namespaces, you defeat the whole point of it. If you need multiple namespaces, then use the old syntax. For those 99.9% of times when only one namespace is used, then the nesting can be reduced down.

I'd actually take this proposal one step further and allow the removal of {} for the type too if only one type is needed in the file:

using System;
public class Company.Project.Product;

private readonly bool _someFlag;

public Product() => ...

etc

@HaloFour
Copy link
Contributor

I like this idea but only when it's limited specifically so that namespace must the first directive and it is the only namespace declaration within that file. At that point it's similar to the Java package directive, except without all of the forced folder structure nonsense.

@gordanr
Copy link

gordanr commented Feb 21, 2017

@HaloFour why must be the first directive? Isn't it enough to be the only namespace declaration within that file?

I like this idea but only when it's limited specifically so that namespace must the first directive and it is the only namespace declaration within that file. At that point it's similar to the Java package directive, except without all of the forced folder structure nonsense.

@iam3yal
Copy link
Contributor

iam3yal commented Feb 21, 2017

@gordanr Probably but why would you put it elsewhere?

@HaloFour
Copy link
Contributor

@gordanr

why must be the first directive? Isn't it enough to be the only namespace declaration within that file?

I think it helps the directive to stand out. Otherwise it might get lost after a long list of using directives and look like a source file with no namespace directive.

@gordanr
Copy link

gordanr commented Feb 21, 2017

@eyalsk It is not so important, but maybe someone wants to put using before namespace.
@HaloFour Yes. If the using list is long, It's better to put namespace first. But for shorter list, I prefer using first. Not so important.

@YaakovDavis
Copy link

YaakovDavis commented Feb 21, 2017

eliminate namespace keyword from *.cs files at all and map fully qualified class name to physical folder structure instead like java does

No need to import bad ideas from Java.
In C# projects, you can arrange files freely without breaking code (or relying on automatic IDE refactorings which might or not work, depending on the your code state).

Also, In Java projects you typically have gazillion of namespaces, precisely because of this structure. No thanks, I don't want a C# mode that enables this messiness.

Regarding this proposal, I'd like to keep having the freedom to combine multiple namespaces in 1 file. I use it for related extension classes, where each of the classes is defined in a different namespace (the same namespace as of the class it extends).

@gordanr
Copy link

gordanr commented Feb 21, 2017

Can anyone see any conflict with partial classes?

Also, I am not sure is the proposal's name appropriate. I have no idea how, but probably can be better.

@jnm2
Copy link
Contributor

jnm2 commented Feb 21, 2017

For all my files that have a single namespace (which is all of them so far, personal and work, including every file I've ever edited or read in an open source project), nothing would make me happier than this:

using System;

public class My.Namespace.ClassName
{

}

And I do mean nothing. :-)

@bomzj
Copy link
Author

bomzj commented Feb 21, 2017

@jnm2

This might be good but Visual Studio does not do this automatically, so you have to amend it every time you create class.

@jnm2
Copy link
Contributor

jnm2 commented Feb 21, 2017

@bomzj First things first. :-) If the language supports it, Visual Studio templates will be able to be created eventually.

(Speaking of which, for every console app I ever create, I add public static in front of the class, public in front of Main, usually delete the args parameter, and delete the usings. Otherwise, ReSharper lights everything up and complains that it doesn't match my code style settings, which is true. Plus it's totally easy to add usings as you type. I've been meaning to edit the template for myself. But this is another story.)

@ig-sinicyn
Copy link

@bomzj

Vote down. Placing using inside a namespace may result in breaking change for existing code.

Except for this the proposal has no benefit but adding one more subtle syntax for already existing feature. We have 8 (or nine?) ways to declare a property now. Isn't it enough? 😕

@jnm2
Copy link
Contributor

jnm2 commented Feb 21, 2017

@ig-sinicyn I don't know if it deserves a down vote for those reasons. It's not a breaking change to any existing code. If you edit your code to start using the new syntax in the proposal, that's no more breaking than if you edit your code to put your usings inside.

Also, less indent and fewer curly braces to worry about are benefits for sure.

@HaloFour
Copy link
Contributor

@ig-sinicyn

Given that this proposal requires explicitly using a new syntax which wasn't previously legal this wouldn't result in any breaking changes to existing code.

The proposal is indeed minor, but I think reduction of noise indentation is not a bad thing. For the vast majority of source files it's a wasted block of horizontal space, particularly given how rare it actually is to have more than one namespace (nested or otherwise) in a single source file.

@ig-sinicyn
Copy link

ig-sinicyn commented Feb 21, 2017

@HaloFour

Ok, let me reformulate in the following way:

  1. This proposal introduces change in type resolution logic that will be unexpected by most of C# developers.

  2. This proposal continues series of "just because we can" proposals. It has no real use-case behind it, it adds no benefit but saving two chars and it makes language more complex due to perl-style 'There's more than one way to do it' motto. It's all ok but c# is not perl.
    There's a lot of doomed languages filled with insane and controversal features that no one can explain or deal with.
    At the same time there are a very few languages with clean and sane design, obvious syntax and (almost) without hype-inspired design process. As for me there's no sense in implementing proposals that fails '-100 points' rule and will move c# into the first group:)

@ziaulhasanhamim
Copy link

ziaulhasanhamim commented Jul 9, 2021

File scoped static classes would be great too like F# modules.
This is a cqrs example

namespace Users
{
    public static class Create
    {
        public class Command
        {
            ....
        }
        public class Handler
        {
            ....
        }
    }
}

With scoped static class

module Users.Create;
public class Command
{
     ....
}
public class Handler
{
    ....
}

@julealgon
Copy link

For all my files that have a single namespace (which is all of them so far, personal and work, including every file I've ever edited or read in an open source project), nothing would make me happier than this:

using System;

public class My.Namespace.ClassName
{

}

And I do mean nothing. :-)

This thread is huge so apologies if this was already brought up.

While I agree with you @jnm2 that this would be a lot cleaner/simpler, it removes the possibility of adding using namespaces inside the namespace, like this:

namespace My.Namespace
{
    using System;

    public class ClassName
    {

    }
}

If the syntax you are proposing was to be allowed, I'd also like to see this being possible:

public class My.Namespace.ClassName
{
    using System;
 
    public ClassName()
    {
        ...
    }

    public string SomeProperty { get; set; }

    }
}

(i.e. namespace references inside the class).

@jnm2
Copy link
Contributor

jnm2 commented Jul 27, 2021

Another problem with what I wanted is that it's not clear how it could work with nested classes, a prime use case for me. I think this would be best as a shortcut for wrapping with partial class C:

namespace A.B;

class C.D
{

@CleanCodeX
Copy link

As of now, file scoped Namespaces don't work with VS2019 (both preview and non-preview).
Is that intended and FSN considered to be a VS2022-only feature?
If so, why isn't it properly documented? (at least I couldn't find any information about it)
If not, why isn't it compiling in 2019?

@CyrusNajmabadi
Copy link
Member

@CleanCodeX FileScopedNamespaces are part of C# 10. So you'll need to use a tool that supports that version of the language. All our IDE support went into the 17.0.x line (i.e. VS2022).

@CleanCodeX
Copy link

CleanCodeX commented Sep 29, 2021

It seems, people (including me) are a bit confused by the fact that some features are a feature of .NET and some of the C# compiler.
Thanks for pointing it out. Sadly I could not find any list of C# 10 compiler features (not just NET6). Is there any list available what the C# 10 compiler will support for the final release? All lists I found do not distinguish between C# 10 and .NET itself. The NET6/C#10 feature lists I found are often labeled just as "C# 10 features" or "NET6 features" but obviously that isn't technically true.

@CleanCodeX
Copy link

CleanCodeX commented Sep 29, 2021

@CleanCodeX FileScopedNamespaces are part of C# 10. So you'll need to use a tool that supports that version of the language. All our IDE support went into the 17.0.x line (i.e. VS2022).

My confusion is based on that:
A female program manager from Microsoft (don't remember her name) said in a Youtube Dotnet stream: "if you can use the 'global using' keyword combination, you're using c#10." But, global usings work in VS2019, so c#10 support seems to be there and therefore FSN should also work, at least that was what I thought.

@333fred
Copy link
Member

333fred commented Sep 29, 2021

There were some preview features of 10 that went into VS2019. But that's all.

@CleanCodeX
Copy link

Will FSN find their way into VS2019 as well?

@CyrusNajmabadi
Copy link
Member

CyrusNajmabadi commented Sep 29, 2021

Will FSN find their way into VS2019 as well?

No. VS2019 is effectively locked down now, with only highly critical fixes being made there (think "bad crashes affecting millions"). Shipping preview features in it will not happen.

@CyrusNajmabadi
Copy link
Member

"if you can use the 'global using' keyword combination, you're using c#10."

This is correct. 'global usings' are part of C# 10.

But, global usings work in VS2019,

VS2019 has 'preview' support for 'some' C# 10 features. But it doesn't have 'final' support for 'all' c# 10 features. 'preview' allows people to test things out and gives us a chance to make thigns available earlier to get feedback. But not all features will make it into preview in a particular VS release. It will depend on when in the schedule we implement the feature in preview and how that aligns with particular VS schedules.

so c#10 support seems to be there and therefore FSN should also work, at least that was what I thought.

This is not something we guarantee. As per above, not all features make it into a preview release for a particular VS build. global-usings made it into a preview build for VS2019, FSN made it into a preview build for VS2022.

@CleanCodeX
Copy link

Will FSN find their way into VS2019 as well?

No. VS2019 is effectively locked down now, with only highly critical fixes being made there (think "bad crashes affecting millions"). Shipping preview features in it will not happen.

Sorry, I meant will FSN find their way into VS2019 preview as well?

@CyrusNajmabadi
Copy link
Member

Sorry, I meant will FSN find their way into VS2019 preview as well?

No.

@mungojam
Copy link

Shouldn't this issue be closed? It went live in the last release right?

@CyrusNajmabadi
Copy link
Member

The ecma spec has not been updated for this yet, so it is not finished @mungojam .

@Eli-Black-Work
Copy link

@mungojam FYI, that's what the "Implemented needs ECMA spec" label on this issue means, although of course that's easily missed if one doesn't know to look for it 🙂

@mungojam
Copy link

mungojam commented Oct 3, 2022

@mungojam FYI, that's what the "Implemented needs ECMA spec" label on this issue means, although of course that's easily missed if one doesn't know to look for it 🙂

That makes sense. I actually came here because it was listed on the future roadmap of c# changes and showing as open. Should it be removed from there?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature Request Implemented Needs ECMA Spec This feature has been implemented in C#, but still needs to be merged into the ECMA specification Proposal champion
Projects
None yet
Development

No branches or pull requests