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

Making global namespaces available to an assembly? good idea? useful? what do you think? #14547

Closed
iam3yal opened this issue Oct 16, 2016 · 25 comments

Comments

@iam3yal
Copy link

iam3yal commented Oct 16, 2016

Hey guys,

Many times, mostly in my testing projects I need to repeat myself over and over again and I have a bunch of namespaces that exists in all of my testing files.

Something like this:

using System;
using System.IO;

using Exceptions;

using FluentAssertions;

using Testing.Utilities.ReSharper;

using Xbehave;

using static Testing.Utilities.Lambda;

Opiumtm's approach:

I've modified the syntax slightly.

// FileX.cs
namespace MyProject
{
    using SomeUsings = {
        System,
        System.IO,
        System.Xml,
        System.Linq,
        Testing.Utilities.Lambda
    };
}

// FileY.cs
using MyProject.SomeUsings;

Restrictions:

  1. The using group cannot contain another using group.
  2. The same name cannot be used twice within the same namespace, e.g., MyProject.SomeUsings cannot be used again but MyProject2.SomeUsings should be valid.
  3. Using groups are only available to the project in which they are declared.

Zippec's approach:

New compiler option /projectusing:<string>
New preprocessor directive #projectusings
New section in project files that would be passed to compiler

Both approaches are good enough for me and I like them both, personally I'd go with @Opiumtm suggestion.

Edit:

  1. Remove the restriction to put it in the AssemblyInfo.cs.
  2. Remove the opt-in/out of this option.
  3. Added @zippec approach.
  4. Added @Opiumtm approach.
  5. Removed my original idea from the post.
  6. Added restrictions section to @Opiumtm's approach.
@alrz
Copy link
Member

alrz commented Oct 16, 2016

Related: #2044

@iam3yal
Copy link
Author

iam3yal commented Oct 16, 2016

@alrz yeah it's related but very different approach, will see what people think about this.

@svick
Copy link
Contributor

svick commented Oct 16, 2016

be declared only in the AssemblyInfo.cs file

That doesn't sound like a good idea to me. AssemblyInfo.cs is currently not special in any way and you want to explicitly name it in the specification? Besides, when compiling using the Roslyn API, there may not even be file names.


using global off

C# currently does not have dialects, this does not look like a good reason to start to me. Why would it need to be opt-in or opt-out in the first place? People who don't like it can just not use it, like with all the various features that C# currently has.

@alrz
Copy link
Member

alrz commented Oct 16, 2016

Note: VB supports this through imports compiler flag. You can configure global imports in Project Properties > References.

@iam3yal
Copy link
Author

iam3yal commented Oct 16, 2016

@svick

That doesn't sound like a good idea to me. AssemblyInfo.cs is currently not special in any way and you want to explicitly name it in the specification? Besides, when compiling using the Roslyn API, there may not even be file names.

You're right, then we can just put these namespaces everywhere we would like and then opt-in to them in other files.

C# currently does not have dialects, this does not look like a good reason to start to me. Why would it need to be opt-in or opt-out in the first place? People who don't like it can just not use it, like with all the various features that C# currently has.

Sure, I've just thrown some ideas to see what the community think. :)

@vbcodec I don't think that anything that touches the file system in such a way is a great idea, I don't think I want C# to be like C++/TypeScript, I have enough on my plate dealing with them.

@alrz Is it strictly VB feature?

@vbcodec
Copy link

vbcodec commented Oct 16, 2016

switch to VB, and go to project's settings where you can set globally available namespaces

@iam3yal
Copy link
Author

iam3yal commented Oct 16, 2016

@vbcodec What do you mean by switch to VB? I get the point where VB has this feature but why would it be strictly a VB thing?

I'm not a VB programmer and I wouldn't convert projects to VB just to have this feature, that's kinda silly, it's like telling people to convert their projects to another language just because this language has a feature they need or not but they still think that it can be useful to add it to their favorite language.

People hate options? or what's the issue?

@jveselka
Copy link

I wouldn't tie this information to AssemblyInfo as it isn't in any way special from the compiler point of view.

What sounds reasonable to me is that it should:

  • Not be part of the language per se
  • Not be tied to specific project structure or IDE
  • Be explicitly stated in every file to avoid confusion

Which leads me to this design (intentionally similar to define):

  • New compiler option /projectusing:<string>
  • New preprocessor directive #projectusings
  • New section in project files that would be passed to compiler

@Joe4evr
Copy link

Joe4evr commented Oct 17, 2016

I kinda like that approach. If I understand correctly, you can still omit #projectusings in cases where you're working in a file and you don't need anything imported (which will mean less clutter in IntelliSense).

If implemented that way, I'd like to suggest for the IDE experience: Hovering over the #projectusings directive should show the namespaces that are being imported this way, just like how there's a view of code in a collapsed piece of text by hovering over the ... part.

@jveselka
Copy link

If I understand correctly, you can still omit #projectusings in cases where you're working in a file and you don't need anything imported

Exactly

I'd like to suggest for the IDE experience: Hovering over the #projectusings directive should show the namespaces that are being imported this way

That would be awesome

@Opiumtm
Copy link

Opiumtm commented Oct 17, 2016

I think it would be more interesting to use different approach.

Introduce "using batches" concept (using as language construct):

// put at any C# file

namespace MyProject
{
    using as DefaultUsings {
        System,
        System.IO,
        System.Xml,
        System.Linq,
        static Testing.Utilities.Lambda
    };
}

And then you can just reference all bunched together usings in one line

// prefixed with "MyProject" because usings batch is declared inside namespace!
using MyProject.DefaultUsings;

Using batches shouldn't be exported in binary DLL. They should be meaningful only for current project source files.

@iam3yal
Copy link
Author

iam3yal commented Oct 17, 2016

@Opiumtm hmm this is pretty cool! but I'd go with the following syntax:

using SomeUsings = {
    System,
    System.IO,
    System.Xml,
    System.Linq,
    Testing.Utilities.Lambda
};

I think that the static modifier is redundant because the compiler can infer that it's a static class and do the appropriate thing but that's just an assumption.

Anyway I like this because it will allow us to group multiple using statements and import them in other places, however, I see two issues here:

  1. Discovery: The IDE will need to show us the in the tooltip where it's declared and what using statements it contains.
  2. Ambiguity: What's the correct resolution if the same name is used for more than one group? do they merge?

@Opiumtm
Copy link

Opiumtm commented Oct 17, 2016

@eyalsk

Ambiguity: What's the correct resolution if the same name is used for more than one group? do they merge?

Yes, they should merge and throw compilation warning. To fight ambiguity to some degree, batch usings can be declared inside namespace and then referenced as if it's a part of namespace.

Things that are legal, but potentially problematic ("usings batch" with the same name inside same namespace declared and merged across different source files is a potential maintainability problem) should throw warning at compilation. So, developer would see it's a legal, but definitely bad practice.

@iam3yal
Copy link
Author

iam3yal commented Oct 17, 2016

@Opiumtm Warnings can be left to analyzers. :)

@Opiumtm
Copy link

Opiumtm commented Oct 17, 2016

@eyalsk And I think, recursive using batches (using batch that contains another using batch) should be forbidden as it would introduce complex namespace dependency graph with possible cycles. So, using batches should contain only regular namespaces or static types.

@iam3yal
Copy link
Author

iam3yal commented Oct 17, 2016

@Opiumtm Yeah, I think so too. :)

@ashmind
Copy link
Contributor

ashmind commented Oct 18, 2016

I agree with having it explicit, and in-language — if #projectusings is in the project file that means no "Find Usages" to find that namespace, no "Rename", no IntelliSense.

But not sure how much benefit named batches would bring over a default set, can't think of many use cases. Something simple like using default = { System.IO, ... }; in any file (probably AssemblyInfo, but can be anything) and then using default; in all other files could be just as good.

@jveselka
Copy link

jveselka commented Oct 18, 2016

Ambiguity: What's the correct resolution if the same name is used for more than one group? do they merge?

I think it should be illegal. Merge would be unnecessary complexity that doesn't add any value.

@iam3yal
Copy link
Author

iam3yal commented Oct 18, 2016

@zippec Well, it has some value but I agree with you, I don't think it should be allowed.

@tamlin-mike
Copy link

Just brainstorming here, but what about calling this "namespacegroup"? It would communicate what it is, and make it impossible for older compilers to understand (since it would be a new keyword, and as explained below also a syntax error).

To be 100% clear, what I had in mind is (at point-of-use):

using namespacegroup Foo.Bar.MyNamespaceGroup;

It would not increase count of '#' directives (those should be kept on a very short leach), while make it 100% clear for even a casual observer what's going on.

Some of the remaining issues would be to define a namespacegroup, specification of such a beast, and how to specify specific types by "whole path". Would f.ex. "global::MyNamespaceGroup.SomeType" be valid after such a fictional using directive?

I like the idea, if nothing else for the intellectual challenge, but I also note Here Be Dragons! :-)

@iam3yal
Copy link
Author

iam3yal commented Oct 21, 2016

@tamlin-mike

Just brainstorming here, but what about calling this "namespacegroup"? It would communicate what it is, and make it impossible for older compilers to understand (since it would be a new keyword, and as explained below also a syntax error).

To be 100% clear, what I had in mind is (at point-of-use):

using namespacegroup Foo.Bar.MyNamespaceGroup;

Why do we need to introduce a new keyword? it would be an error anyhow with or without the new keyword and the if you already used the name for a namespace in the same assembly then you can't use it for the namespace group,

BTW, it's not really clear whether you support @zippec's idea or @Opiumtm's idea, I mean in the first part of your post it seems like you relate to @Opiumtm's idea but then you mentioned directives and this is another idea so I'm not sure.

Anyway, I hope I understood you, probably not? 😄

@tamlin-mike
Copy link

@eyalsk
The reason for a new keyword would be to make it easier for everyone (perhaps esp. maintainers, or simply just viewers, of code using the construct) to understand it.
A "namespacegroup" would in my mind be pretty much like a C/C++ header file only including other headers. It would be a single specific purpose.

With a standing out keyword, it would not provide any risk of surprises (this is something I consider vitally important).

I like the concept of being able to reduce amount of "includes" (a.k.a. "using"), but when it comes to lumping multiple namespace includes into a single include, I think it would be better to be explicit about what is going on - hence the "*group" keyword idea.

@iam3yal
Copy link
Author

iam3yal commented Oct 22, 2016

@tamlin-mike I'm not quite sure what surprises you think you may run into?

The IDE can help by displaying the using statements it imports, including the file where the group is defined inside a tooltip and finally it can color it differently so people would know it's not a regular using statement.

Not to mention that namespacegroup doesn't make sense because it can also contain static classes so maybe 'using group Foo.Bar.MyNamespaceGroup;` but again, I don't think it's really necessary. :)

@tamlin-mike
Copy link

@Eylask: The point I was trying to make was that that the keyword would make it stand out (even without a "fancy" IDE - think: looking at the code in Notepad).

I willingly admit, I haven't given this the amount of thought it probably deserve, but I'm still quite convinced this feature deserves a keyword of its own (and that it only is used to introduce namespaces - nothing else).

Perhaps my view is oversimplifying the potential issues (wouldn't be the first time).

@iam3yal
Copy link
Author

iam3yal commented Oct 22, 2016

@tamlin-mike maybe, that's for the design team to decide iff this feature will ever make it.. haha.. :)

@iam3yal iam3yal closed this as completed Jun 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests