dotnet / csharplang

The official repo for the design of the C# programming language
11.34k stars 1.02k 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:

alrz commented 6 years ago

Assembly attributes [assembly: Foo] would be disallowed in the presence of a namespace directive?

jnm2 commented 6 years ago

I never understood why namespace directives were relevant to the placement of assembly: attributes.

alrz commented 6 years ago

currently you can't have assembly attributes after any namespace declaration. usings come first, then assembly attributes, and finally namespace decls. with the requirement of namespace directives being the very first part of the compilation unit (like Java's package), following the existing rules, you can't use assembly attributes and namespace decls at the same time.

jnm2 commented 6 years ago

I know, and I honestly don't understand why not. You're clearly targeting the assembly either way.

Joe4evr commented 6 years ago

Wouldn't one ideally list all their assembly-wide attributes in a dedicated file? (Usually AssemblyInfo.cs, which although missing from .NET Core-style project templates, is easy enough to add manually.)

alrz commented 6 years ago

@Joe4evr

Wouldn't one ideally list all their assembly-wide attributes in a dedicated file?

That would be a convention vs. what's "possible" in the language.

jnm2 commented 6 years ago

@Joe4evr I've been known to put things like [assembly: DefaultCharSet] other places.

Denis535 commented 6 years ago

In Java I hate package for their naming convention. In C# I hate namespace for excessive hierarchy. Change package naming conventions is too late. But add new syntax is always possible, so I hope for you guys. Sorry for offtop. I just always wanted this syntax.

mharasimowicz commented 6 years ago

@jnm2

Can we just remove need of curly brackets? It shouldn't change compiler logic much:

using System;

namespace My.Namespace public class ClassName
{

}
jnm2 commented 6 years ago

@mharasimowicz Hmm. For some reason I'm not liking that.

CyrusNajmabadi commented 6 years ago

It shouldn't change compiler logic much:

It changes every piece of code that currently assumes the containing namespace can be found by just walking upwards to find a parenting namespace declaration node.

But add new syntax is always possible

It's always possible, but in a similar fashion, if it's not valuable enough it's not worthwhile to change things and introduce dialects. C# is 17 years old now. Changing things is fine, if it has substantial enough benefits. Here, i just don't see it.

--

Or, put another way: often times there are things we'd like to do with syntax. However, we try to tie them to some substantially new thing that doesn't already exist today.

Another way to think about it is this: top level syntax is not where people spend the majority of their time. It's inside a method body where most of the action happens, and where you can get most of the bang for your buck around syntax changes.

CyrusNajmabadi commented 6 years ago

@mharasimowicz Hmm. For some reason I'm not liking that.

Agreed. That looks terrible to me.

MgSam commented 6 years ago

Another way to think about it is this: top level syntax is not where people spend the majority of their time. It's inside a method body where most of the action happens, and where you can get most of the bang for your buck around syntax changes.

@CyrusNajmabadi Every method body you're ever written in C# has an unnecessary extra level of indentation because of the namespace. Even when the standard practice since C# 1.0 has been one namespace per file.

Sure, maybe that extra layer of whitespace doesn't matter when you're at a desktop with a 30 inch monitor, but when you're writing code on a small laptop screen, for example, every character on the line matters.

alrz commented 6 years ago

maybe that extra layer of whitespace doesn't matter when you're at a desktop with a 30 inch monitor, but when you're writing code on a small laptop screen, for example, every character on the line matters.

Not to mention, GitHub PRs have a fixed width. Less indentation means less need for wrapping so you'd have cleaner code at the end.

CyrusNajmabadi commented 6 years ago

but when you're writing code on a small laptop screen, for example, every character on the line matters.

Ask anyone on the roslyn team. I do 100% of my development on a 14" laptop :) Literally every line of Roslyn code i've ever written has been in a window this size:

image

Seriously, the entire team will back me up that this is how i code. I actually prefer this because it lets me focus on what matters, without distraction.

Every method body you're ever written in C# has an unnecessary extra level of indentation because of the namespace

The important bit for me is this: i never write that. It's not like i'm typing spacespacespacespace. I'm typing my actual code, and things like indentation are being handled for my by my environment. It's not something I need to be involved with.

Even when the standard practice since C# 1.0 has been one namespace per file.

Yes. And that's a very good point. It's been the standard practice since c# 1.0. It's not like people were writing code like this all that time:

namespace A.B.C
{
class D
{
}
}

People have been writing C# it with the indentation all this time. I don't see why we'e now 17 years into things want to introduce a new dialect and spend all that engineering effort to something that doesn't seem to actually substantively improve the expressiveness of the language, while actually introducing a different dialect.

Again, if this were C# 1.0/2.0, i'd likely feel different. But, frankly, i'd rather hte effort be spent on things that directly lead to significantly improved programs. i.e. things that affect the actual code that is written, not the presentation of that code.

If you really want to not have indentation here, don't add a language feature, instead add a formatting option. IT will be literally 1/100th the cost, and would easily be accepted over trying to actually change the language.

iam3yal commented 6 years ago

@CyrusNajmabadi

Well, one way we might be able to solve this is through (future, aka 100 years 😆) source generation.

With something like this:

[Namespace("A.B.C")]
class D
{
}

Just an idea.

Pzixel commented 6 years ago

What about rule if class is not in namespace, then just use current project path? For example:

/MyApp/My/Cool/Path/Program.cs

using System;

class Program
{
   static void Main(string[] args)
   {
   }
}

become:

using System;

namespace MyApp.My.Cool.Path
{
   class Program
   {
      static void Main(string[] args)
      {
      }
   }
}

If people don't like default naming convention physical path is actual namespace path, then they could just write it explicitely:

using System;

namespace MyApp.I.Dont.Like.Your.Convention
{
   class Program
   {
      static void Main(string[] args)
      {
      }
   }
}
alrz commented 6 years ago

@Pzixel It's breaking. top-level types belong to the global namespace.

Pzixel commented 6 years ago

@alrz but we may change context via something like

namespace default;
using System;

public class Product
{ 
    ...
}

it's an extension of original proposal, where we don't specify namespace manually.

Otherwise we have no option but write rules that namespace declaration adds no intendation. It seems easier but harder to read than one declaration on the first line.

svick commented 6 years ago

@Pzixel What is a "current project path"? Consider:

  1. The C# compiler doesn't have a notion of project, only a set of files that together form a compilation. (The notion of project only exists in MSBuild and Visual Studio.)
  2. C# projects often aren't structured the same as namespaces. For example, if my project is named Foo, files in the Foo.Bar namespace might be under the path of src/Bar. Though there isn't a single standard way to structure a C# project (precisely because it didn't matter to the compiler).
  3. The path seems to be relative, but relative to what?
  4. Multiple projects can include the same file. Does that mean the namespace of a single file can change, depending on which project it's included in?
Pzixel commented 6 years ago
  1. C# compiler does have a notion of project, see Roslyn API.
  2. If C# project is not structured as namespaces then it's not very well designed. Anyway, you still have ol' good way to declare explicit namespace if you want. I'm just talking about "omit declaration when convention is in use", like ASP.Net MVC naming does.
  3. Relative to .csproj root.
  4. I don't see a lot of this stuff, but yes, it will be in different namespaces. Especially that having two same full qualified names in one application is not very good. So having one single file to be placed in two different namespaces is considered as an advantage.
svick commented 6 years ago

@Pzixel

C# compiler does have a notion of project, see Roslyn API.

You can't specify a project when compiling with csc or when you use Microsoft.CodeAnalysis.CSharp.CSharpCompilation. Sure, there is Microsoft.CodeAnalysis.Project, but that's part of the Roslyn Workspaces API, which is not really part of the compiler itself.

Relative to .csproj root.

Then what happens when the relative path is something like ..\..\Common\src\Microsoft\Internal\EmptyArray.cs?

alrz commented 6 years ago

@Pzixel

But honestly, your proposal doesn't make "file-scoped namespaces" as described in this thread, any easier or better, if it doesn't make it harder to implement. Note that the concerns mentioned in https://github.com/dotnet/csharplang/issues/137#issuecomment-345550024 still applies to namespace default in one way or another.

Pzixel commented 6 years ago

@svick

Then what happens when the relative path is something like ....\Common\src\Microsoft\Internal\EmptyArray.cs?

Nah, you beat me :)

@alrz I agree, but if it worth we can extend this logic that namespace may be just specified once in the beginning of the file. I also agree, that probably the best we can do is no-op or custom code style. However, probably there is some alternative way we don't see yet.

DavidArno commented 6 years ago

@Pzixel,

Like others, I don't feel that namespace default adds anything but extra complication to the original proposal:

namespace Company.Project
using System;

public class Product
{ 
    ...
}

which is simple and elegant.

And in my view, @CyrusNajmabadi's concern re "It changes every piece of code that currently assumes the containing namespace can be found by just walking upwards to find a parenting namespace declaration node." is non sequitur. Firstly, the namespace node could still exist in the same place in the syntax tree, and secondly, since namespaces can be nested, walking up that tree to that first encountered namespace node is not currently a reliable way of getting the namespace.

And even worse is his hack solution of just not indenting the type blocks inside that namespace. An ugly botch is not a good alternative to the elegance of this proposal I do not think that the idea of not indenting within the namespace block is a nice solution. It runs counter to the near-universal convention of how C# code is laid out. I think it very inelegant compared with this proposal.

(Edited as my original comment was far too much an attack on Cyrus, rather than explaining why I didn't like it).

jnm2 commented 6 years ago

And even worse is his hack solution

ugly botch

If I didn't know better I'd think you had a chip on your shoulder for someone... 😁

DavidArno commented 6 years ago

Hmm, when you selectively quote my comment, it does seem somewhat negative 😆

jnm2 commented 6 years ago

I was going to quote the whole thing at first, but I felt like that was a fair summary. 😆 Can easily fix...

DavidArno commented 6 years ago

Oh, no, it's OK. It's not unfair selective quoting. Your point is well made. I need to be more careful with my enthusiasm to be, well rude (especially to @CyrusNajmabadi, who seems all too often to be the target of that rudeness).

I have updated it to hopefully be less aggressive.

CyrusNajmabadi commented 6 years ago

is non sequitur.

It's really not. Trust me, i've written a bunch of code that works that way :)

I do not think that the idea of not indenting within the namespace block is a nice solution. It runs counter to the near-universal convention of how C# code is laid out.

Right. People indent namespaces today. This whole proposal is a way to make it so people don't have to do that. IN that regard, this proposal itself is counter to the near-universal convention of how C# is laid out. Given that some people want this, i don't know why we need it from a new language feature (cost: roughly 1 million cybucks) vs just submitting a PR for a formatting feeature (cost: roughly 1k cybucks). Seriously, if you don't want indented classes, and you feel like you're wasting horizontal space across the entire project, and you're ok with your code not looking like the near-universal patterns of the rest of C# out there: Then just make a formatting option. :)

CyrusNajmabadi commented 6 years ago

FWIW, i didn't take it as an attack. And, to address hte main point:

An ugly botch is not a good alternative to the elegance of this proposal

Yes, it really is. Why? Because forcing a ton of time and effort to get almost the same result that you can effectively get today is a bad decision. Think about all the times you go "man... i wish the team could hurry up and get around to active patterns". Now think about what a feature like this is. To do it, it would occupy someone's time great. They have to get the proposal all the way through the LDM. Then they have to change the syntax model of the compiler to support it. Then they have to touch everything in the compiler that deals with namespaces to make sure it works. That means writing a test for every possible language feature that can be affected by namespaces.

Then, once that is done, every IDE feature needs to be tested in the context of this this new namespace construct to make sure they do the right thing. And features like formatting/rename/etc have to be updated to do the right thing for them.

That's literally man-weeks of effort. To get you to the point where all you've gained is that you don't have indent your nested constructs, and you can avoid an extra { } by replacing it with a ;.

Yes, this proposal is the most 'elegant'. Great. That elegance cost weeks of time that could be spent providing a lot more bang for the buck for the user. That's bad engineering IMO, and not the right decision for the team right now.

--

Note: if this were to be done, i would much rather have be as part of some sort of cohesive and invested effort in some sort of C#-light dialect. Similar to #light in F#. In other words, really attack the overall verbosity/nesting issue with a set of cohesive feature that overall worked together. Then there could be economies of scale going on. Instead of someone having to pass over the entire IDE codebase just to test out one thing, they could instead collect a bunch of syntactic improvements together and only spend a few percent more time to get a lot more features in the hands of users. That's something i can at least get behind given the size of the improvement that would come along with the cost of the work.

Joe4evr commented 6 years ago

if this were to be done, i would much rather have be as part of some sort of cohesive and invested effort in some sort of C#-light dialect

I thought the LDM was vehemently against making different dialects of the language.

CyrusNajmabadi commented 6 years ago

I thought the LDM was vehemently against making different dialects of the language.

I think they are :) But since we're discussing dialects with this proposal anyways... :)

iam3yal commented 6 years ago

Another way to solve this is add a different representation of the source code to the IDE where certain things are removed, something like "compact/lightweight view" that doesn't show namespaces and maybe other things.

I understand that when browsing the source code through different tools other than VS it would still be a distraction but at least when you're working on the code you could have the option not to show it.

paulirwin commented 6 years ago

There's been a lot of different proposals on this thread, but I'm giving a +1 to @HaloFour's suggestion that we treat this like the Java package directive: one per file, must be first directive in the file, i.e.:

namespace My.Company;

using System;

public class MyClass {
    ...
}

And of course allow the old container syntax so that this is not a breaking change.

Benefits: less indentation, less horizontal scrolling, better enforcement of one-namespace-per-file per StyleCop rule SA1403. I would exclusively use this feature if it were available to me. I cannot recall a single time that I've needed multiple namespaces in a file, so this would be a very welcome change.

FWIW, I would also use the public class My.Company.MyClass alternative if that's the decision. I like the namespace directive better so that you don't have to repeat it if you have multiple classes in a file, which I feel is much more common than multiple namespaces.

CyrusNajmabadi commented 6 years ago

There's been a lot of different proposals on this thread, but I'm giving a +1 to @HaloFour's suggestion that we treat this like the Java package directive: one per file, must be first directive in the file, i.e.:

namespace My.Company;

using System;

public class MyClass {
    ...
}

So you can't do:

using System;

namespace My.Company;

public class MyClass {
    ...
}

?

That means a lot of code won't be able to easily transfer over. As moving the using from outside the namespace to inside can change its meaning, causing code to break.

CyrusNajmabadi commented 6 years ago

Benefits: less indentation, less horizontal scrolling, better enforcement of one-namespace-per-file per StyleCop rule SA1403.

None of these need a language change. Less indentation can be fixed at 1/1000th the cost by just chanding the formatting.

Less horizontal scrolling would call out of the formatting change.

CyrusNajmabadi commented 6 years ago

Seriously. To put it in perspective. This feature could have been done in an hour or so the day this was proposed back in the formatting engine. It could have been available months and months ago. Waiting to get it as a language feature means waiting years (or possibly forever) to get it.

If this is important to you, i would recommend just fixing the formatting engine, submitting a PR, and getting the problem solved today instead of hoping this will go anywhere in the next decade :-/

MgSam commented 6 years ago

@CyrusNajmabadi This has been said already, but "fixing" the formatting engine doesn't fix the problem. 99.99% of the code out there will continue to use the Microsoft-recommended style of an extra layer of indentation. And lots of people wouldn't like having a bracketed scope without a corresponding layer of indentation. Your argument is equivalent to "why do we need expression-bodied methods, properties, etc when you could just put the brackets, et al on the same line?"

Why should this have to wait years to happen? You guys are doing point releases now, this could easily be discussed, approved, and implemented in just a couple of LDMs if someone would champion it and then it could be shipped in a point release.

As far as I can see, the real bottleneck is getting someone to champion it. And passing that bar for any community-suggested feature is extremely difficult. Yet silly features like a dictionary literal syntax (that would on rare occasions save you at best a few characters and make no meaningful readability difference) get discussed in LDM solely because Miguel suggested it.

bondsbw commented 6 years ago

@CyrusNajmabadi There are few guidelines which are more consistently applied than indenting inside curly braces. This is true throughout the C# ecosystem and even across nearly all curly-brace languages (despite disagreements on whether to place the opening brace on a separate line).

Suggesting we change such a fundamental idea can't be taken very seriously.

Pzixel commented 6 years ago

@bondsbw I believe @CyrusNajmabadi is saying that it's easier to change these guidelines, than the language. Nothing is preventing you from following this new guideline No spaces after namespace declaration, it's a question about habits.

I originally proposed something that could be worthwhile, however, I've got convinced that it isn't.

If you think that change the language is easier than change people habits - it isn't.

bondsbw commented 6 years ago

@Pzixel This proposal obviously needs to beat others bang-for-buck in order to prioritize it for implementation. I don't think anyone has said otherwise.

Pzixel commented 6 years ago

@CyrusNajmabadi

If this is important to you, i would recommend just fixing the formatting engine, submitting a PR, and getting the problem solved today instead of hoping this will go anywhere in the next decade :-/

Could you link the repository, please? I think it's not Roslyn because it's representation question, while VS sources are not OSS. On the other hand, Roslyn generated code has some indentation rules, so probably it still may be possible to PR in Roslyn repo for this feature.

CyrusNajmabadi commented 6 years ago

Suggesting we change such a fundamental idea can't be taken very seriously.

It's far easier to get people to adopt a new coding style than it is to introduce an entire new language feature and then get people to move to that language feature over the existing one.

Could you link the repository, please? I think it's not Roslyn because it's representation question, while VS sources are not OSS.

This could be done 100% in github.com/dotnet/roslyn. The formatting engine, the editor-config support and the options for VS are all in that repo.

CyrusNajmabadi commented 6 years ago

This proposal obviously needs to beat others bang-for-buck in order to prioritize it for implementation.

I think the problem then is that "changing the formatting engine" kills this, at least in terms of "bang for buck".

Changing the formatting engine:

  1. Cheap.
  2. Solves the issues you guys dislike (excessive indentation).

Changing the language:

  1. Enormously expensive.
  2. Solves the issues you guys dislike (excessive indentation).

So, right off the bat, just changing the formatting engine is super nice.

bondsbw commented 6 years ago

But formatting doesn't just get rid of the indentation. It also breaks one of the most fundamental conventions in curly-brace language programming.

Your "buck" is one that was found in raw sewage. It is technically worth a dollar, but nobody wants it.

CyrusNajmabadi commented 6 years ago

It also breaks one of the most fundamental conventions in curly-brace language programming.

This whole 'feature' is about changing the conventions around C#. So i don't see what the problem is.

We also have already allowed indentation flexibility with curly braces today with 'switch' and the indentation (or not) of the case sections.

--

Finally, i would point out that when it comes to 'curly brace' languages, all you can say about conventions is that there are no 'fundamental' conventions.

For example (from https://en.wikipedia.org/wiki/Indentation_style)

K&R:

while (x == y) {
    something();
    somethingelse();
}

Allman

while (x == y)
{
    something();
    somethingelse();
}

Gnu

while (x == y)
  {
    something();
    somethingelse();
  }

Whitesmith

while (x == y)
    {
    something();
    somethingelse();
    }

Etc. etc.

The only 'fundamental convention' that i've been able to glean about the curly-brace languages is that people do what they want, and you follow the patterns of the codebase you're in.

I see no reason why it would suddenly be a crazy idea that you update the formatting engine to not indent some curly-brace contents especially given C# has already shipped with such an option for many years already.

bondsbw commented 6 years ago

@CyrusNajmabadi Those examples prove my point. All of them use the same indentation for block content (even if the positioning of the braces are different).

Forget braces. Consider languages with begin/end keywords and languages like Python.

The consistent statement across all those styles is that blocks need indentation. But they all allow for statements which modify the current block, such as using, package, program, var, etc.

CyrusNajmabadi commented 6 years ago

And, as i pointed out, that's not universally true. There are already cases today (pun intended) where many do not indent the contents of a block. I see no reason why that is a place where people can have different conventions, but namespaces are somehow sacrosanct and must always be indented.

If you want C# to have a dialect where people don't indent namespaces, just create that dialect. There's no need for new syntax to enable what is just an affect of your editor.

bondsbw commented 6 years ago

I have never written switch blocks with cases that line up with the switch, and I don't recall seeing code that does that. Surely that is an odd convention. At best it is an exception to the rule rather than the rule.

Besides, the contents of the case would be indented, so it is a bit of a different thing anyway.