dotnet / csharplang

The official repo for the design of the C# programming language
11.52k stars 1.03k forks source link

Proposal: File scoped namespaces #137

Open bomzj opened 7 years ago

bomzj commented 7 years ago

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:

ahmedilyasms commented 4 years ago

@ssg - but of course... :( Maybe it should be a lang version thing then... for forwardness compat and not back-compat

ssg commented 4 years ago

@ahmedilyasms That would still break existing code migrating to the new version, which I think is a dealbreaker. None of the new C# features cause something like that.

ahmedilyasms commented 4 years ago

@ssg - we have had this before I guess where certain feature work based on the lang version. But even then so, why would it be a difference in the code gen? It wouldn't AFAIK. We would still support having namespaces in the file but if 1 was NOT supplied, then it should take the default one as defined in the assembly.cs. This thought or approach would cater for both pre and post this proposal :)

CyrusNajmabadi commented 4 years ago

@ahmedilyasms Your feedback is noted. However, what you are asking for is decidedly out of scope for my proposal/championing.

Thanks!

HaloFour commented 4 years ago

@ahmedilyasms

we have had this before I guess where certain feature work based on the lang version

The lang version should light up new features, but not change the behavior of existing code. C# has never required a namespace in a source file, and that has never meant to implicitly put the code under some namespace declared elsewhere. That would be a breaking change and create a dialect in the language.

pavelvondrasek commented 3 years ago

I moved from PHP and as beginner in C# namespace declaration was very ugly for me compared to another parts of language so that I welcome all simplifications which help me with well-arrange simpler code because it's a reason why I moved to C# :)

LarsKemmann commented 3 years ago

Another benefit of this proposal is that it is in line with top-level statements which were introduced recently.

This would also be closer to F#'s namespace syntax, and I think that could be a good thing.

I only partially understand the "root namespace" comments above, but I for one have never seen a C# source file without a namespace declaration. If there is a potential backwards-compatibility issue here, perhaps it could be evaluated against code that's currently in GitHub to see what percentage of "real-world" projects would have a problem?

This would be out of scope of this proposal, but I wonder if the day might come where the namespace declaration is entirely unnecessary since (in my experience) well-structured projects always follow the folder-per-child-namespace pattern. Maybe in .NET 7/C# 11 the compiler could infer the namespace from the project + file path? ๐Ÿ˜€

333fred commented 3 years ago

This would be out of scope of this proposal, but I wonder if the day might come where the namespace declaration is entirely unnecessary since (in my experience) well-structured projects always follow the folder-per-child-namespace pattern. Maybe in .NET 7/C# 11 the compiler could infer the namespace from the project + file path?

I don't think I'll ever support that, at least. Roslyn itself is an example where we have a folder structure that slightly differs from the namespace structure.

LarsKemmann commented 3 years ago

I don't think I'll ever support that, at least. Roslyn itself is an example where we have a folder structure that slightly differs from the namespace structure.

That's totally fair, but also I'm assuming you have explicit namespace declarations within all Roslyn source files. (Bad on me that I haven't checked that assumption, of course.) So if hypothetically such a feature were to be added, it wouldn't impact the existing Roslyn codebase at all. Anyways, just a thought. I really like the theme of this proposal, and my 2ยข is that any change that removes unnecessary curly braces is a welcome one. Of course, that's coming from someone who only gave up wrapping single-line if/else branches with curly braces 3 years ago. ๐Ÿ˜‚ The point is that giving people a choice could be a good thing in that it opens up the language to different ways of viewing the world -- like LINQ did for functional programming -- and that could lead to a new consensus over time about better ways of doing things -- like immutable data & record types.

333fred commented 3 years ago

Discussed in LDM: https://github.com/dotnet/csharplang/blob/master/meetings/2021/LDM-2021-01-13.md#file-scoped-namespaces.

andi0b commented 3 years ago

Can we even go further and make the namespace dependent on the <RootNamespace> in .csproj and the path of the .cs file? It's very common to organize code files with their namespaces into folders, and very often mistakes happen there. This must be optional off course.

/Product.csproj

<RootNamespace>Company.Product</RootNamespace>

/Feature/Implementation.cs

// use namespace without providing the namespace, this doesn't break with existing code, as it was not allowed so far
//
// it would be nice if you wouldn't need it at all, but it would break with existing code.
namespace;

class Implementation 
{
    // this class is now Company.Product.Feature.Implementation
}

It could even go one step further, derive the class name from the file name. This is probably a bad idea, but some ideas for completeness:

/Services/CronService.cs

// pull namespace and class name from filename/path
namespace; 
class;

public static void Run()
{
    // this is now Company.Product.Services.CronService.Run()
}

Off course some other things need to work too

// modifiers
public sealed class;

// structs
struct;

// records
record (double X, double Y);

// derived types, generics, ...
class : IDisposable;
class<T> where T: IDisposable;
bachratyg commented 3 years ago

@andi0b this probably won't happen. AFAIK one of the main goals of C# is that the compilation should never depend on the physical location of the source files (not to mention locations outside the project folder). This is a huge benefit compared to e.g. TypeScript where I need to rewrite all usings (imports) when moving a file.

andi0b commented 3 years ago

@bachratyg: I think you mix two things:

AFAIK one of the main goals of C# is that the compilation should never depend on the physical location of the source files (not to mention locations outside the project folder).

This is true. There are examples where file names or locations of source files already matter:

This a huge benefit compared to e.g. TypeScript where I need to rewrite all usings (imports) when moving a file.

If you want to move files around and keep the name space, you can still use an explicit namespace definition. Most of the time you don't want to keep files with the same namespace in separate folders.

bachratyg commented 3 years ago

@bachratyg: I think you mix two things:

  • csproj file name. Test.csproj will result into setting AssemblyName to Test

That is not a language feature. It's entirely done by msbuild/sdk tooling/Roslyn Workspaces and not by csc. The language has no clue (and rightly so) about the project file format or semantics.

  • CallerFilePathAttribute: the compiler takes file names and add information from there into the code

This is the same category as source information in stack traces: use it for debugging/diagnostics not your core logic otherwise it's your funeral.

If you want to move files around and keep the name space, you can still use an explicit namespace definition. Most of the time you don't want to keep files with the same namespace in separate folders.

I for one frequently factor out files of a feature to subfolders when the folder gets too crowded thus the namespace is usually the prefix of the path. Lots of people in this very same topic also consider java's package equals path as detrimental, I guess they won't prefer it either. That makes the usefulness of your proposal uncertain vs the cost of drastically changing a high level language construct.

ssg commented 3 years ago

@andi0b That has been discussed extensively before, perhaps refer to the previous discussion first: https://github.com/dotnet/csharplang/discussions/2908

ziaulhasanhamim commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

@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 commented 3 years ago

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 commented 3 years ago

@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 commented 3 years ago

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

CleanCodeX commented 3 years ago

Will FSN find their way into VS2019 as well?

CyrusNajmabadi commented 3 years ago

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 commented 3 years ago

"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 commented 3 years ago

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 commented 3 years ago

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

No.

mungojam commented 2 years ago

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

CyrusNajmabadi commented 2 years ago

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

Eli-Black-Work commented 2 years ago

@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 commented 2 years ago

@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?