- "You're muted" "I wanted to be muted"
https://github.com/dotnet/csharplang/blob/master/proposals/csharp-10.0/GlobalUsingDirective.md
Today we discussed the proposed syntax and restrictions on the current feature specification. As checked in today, the proposal
puts global
after the using
directive, which could be potentially ambiguous and require complicated parsing logic, as global
is a valid namespace identifier today. For example, this is valid code:
// Is this a global using alias, or a top-level using variable declaration?
using global myVar = Test.AGlobal;
class Test
{
public static global AGlobal = new global();
}
class global : IDisposable { public void Dispose() {} }
We could potentially resolve this in the same way we did for the record
keyword, which is to forbid types be named global
in
C# 10. We haven't gotten pushback on this approach for record
as a type name so far, which is positive. However, aside from the
ambiguity, there are other reasons to view global
-first as a good thing. global
here is a modifier on the using
, which C#
generally puts before the declaration, not after. We also considered 2 separate but related questions:
- Is
static
a similar modifier? Should it be allowed to come before theusing
as well?- After discussion, we don't believe so.
static
isn't a modifier on theusing
, it fundamentally changes what the meaning of the using is about.
- After discussion, we don't believe so.
- We already have existing modifiers for C# scopes: should we use
internal
as the keyword here?- Using
internal
begs the followup question: what doespublic
on one of theseusing
s mean? What aboutprivate
? We're uncomfortable with the idea of treating these more like types than like macros. This starts to get into a very slippery slope of how we export aliases publicly, can additional constraints be added to aliases, and how does that interact with roles?
- Using
Finally, we discussed the proposed restrictions on the feature. We like them overall: if global
and non-global
using
s can
be interspersed, it could lead to user confusion as to whether regular using
directives can affect global
ones. It also helps
set up a clearly-defined set of scopes. We add a new global
scope that comes before all top-level using
statements today, and
their interactions mirror the interactions of regular using
s statements with those nested in a namespace.
We put global
before using
, but the proposal is otherwise accepted as is.
Continuing with the theme of using
improvements, we also discussed generalized improvements to using
aliases to address a
number of reoccuring complaints over the years with limitations in today's approach. Specifically, using
directives today
cannot reference predefined names like string
, they can't have generic type arguments, they can't use tuple syntax, or use
pointer types (including the C# 9 function pointer syntax). The current proposal allows all of these things, including aliases
for partially-bound type parameters such as using MyDictionary<T> = System.Collections.Generic.Dictionary<int, T>;
. When
combined with the previous global using
feature, enabling this would allow compilation-unit type aliases. Our remaining open
questions here focus again on how we want to push using
s forward in the future:
- If we want to push
using
aliases as real types, then they need to have the ability to expression the same things all other types can, including constraints and variance. If we go this route, we could potentially have a future where you can introduce an alias that adds a new constraint onto an existing type, such as an invariantIEnumerable<T>
alias, or a dictionary that is constrained to onlystruct
-type values. - If we want to push
using
aliases as more macro-expansion, then the ability to expression constraints and variance is a confusing detriment. The type parameter will be substituted at expansion site and we'll error at that point if an illegal substitution is made.
Approach 1 has many followup questions that quickly start to slide into roles territory. Aliases can be used in public API, for
example, so how would we advertise them publicly if the alias has added new constraints? Is it possible for users to introduce
an opaque alias, such as aliasing int
to CustomerId
in such a way as there's no implicit conversion between them? Ultimately,
we think that these problems are better solved by a discrete language feature such as roles, rather than as an expansion on
using
aliases.
using
aliases will be treated more as macro expansions than as real types. We'll check substitutions for concrete types where
we can (such as erroring in the alias itself for using MyList = System.Collections.Generic.List<int*>;
), but for things we
cannot check at the declaration site, we will error at the use site. There is no way to add constraints to a using
alias.