"extern partial" ‒ attach compile time-only attributes to members from external assemblies #8089
Unanswered
IS4Code
asked this question in
Language Ideas
Replies: 1 comment 4 replies
-
What if the member already has an attribute or has nullability defined? |
Beta Was this translation helpful? Give feedback.
4 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Introduction
Many custom attributes are used to affect the interpretation of code at compile time, such as:
[Conditional]
, affecting whether a call to a method is preserved or omitted depending on compilation symbols.[Obsolete]
, displaying a warning/error when a member is used.[Nullable]
and various nullability analysis attributes like[MaybeNull]
etc.[Extension]
,params
:[ParamArray]
, indexers:[DefaultMember]
, tuple elements:[TupleElementNames]
, etc.).While all these attributes are also retained in the metadata and readable at runtime, their main use is to affect C# code using the members where they are attached in a way that does not need to read them at runtime. Additionally, various source analyzers and generators can define their own custom attributes that affect how members are interpreted and processed (for example a compile time-only JSON formatter could use attributes to generate code constructing instances from JSON objects).
In all these cases, it may be useful not only for the code that defines such members to use these attributes, but also for the code that uses them. Imagine:
[Conditional]
, preventing it from being called in your code in specific cases. This is what interceptors can already do, but in a much more complicated way.[Obsolete]
, letting other programmers using the codebase know that it should not be used. This is what source analyzers can already do, but you have to give them the list of obsolete members in some fashion, or use specialized ones for common sets of members.Why?
The usefulness of filling in nullability annotations is obvious, but it is not immediately clear why do more than that. The reasons are:
partial
classes and methods, which also make it possible to add attributes to a member defined in another location (albeit for the same assembly). Using this as the base makes it not only easier to explain to people wanting to use it, but also introduces new language that might make it easier to express similar concepts.Solution:
extern partial
As far as the compiler is concerned, the members are suddenly obsolete (when viewed from the code that specified the
extern partial
types).Details
Types
extern partial
could be used at any non-nested type declaration. Anextern partial
type does not result in any new type in the assembly, instead referring to any externally existing type by the same name (and arity). The types declared above are the usualSystem.Threading.Tasks.Task
(<T>
) and not any new type.extern partial
to identify it, otherwise it results in an error (as there would be no type to augment). If there are multiple matching external types,extern alias
could be used to resolve them.extern partial
type declaration must not have any other modifiers (no explicit visibility,abstract
,sealed
, orstatic
). It also must not have any generic constraints.extern partial
declarations for the same type (with the same effect as being merged together). Additionally, there may also be non-extern partial
definitions for a type with the same name (with or withoutpartial
), but these denote a distinct type (like they do already) and are not affected by theextern partial
declaration.extern partial
type may be aclass
,struct
,enum
,interface
, ordelegate
.record
is not allowed ‒class
orstruct
is enough to match the type (likewise juststruct
instead ofref struct
).Members
extern partial
types are implicitlyextern partial
(including nested types). Explicitly adding this modifier (or justpartial
) is an error.static
, which must match the original member.Custom attributes
extern partial
type, just like for regular types.Syntax-specific attributes
Some attributes are special in C# and cannot be used manually. Whether they are usable or not in this context can be decided on a per-case basis.
this
. This has limited usefulness however, since new extension methods may simply be created.params
. Probably solvable with extension methods too.ValueTuple
could be given element names. This has somewhat greater impact than changing method parameter names.object
could be turned intodynamic
. Probably no significant use cases.Potential extensions
where T : Delegate
orwhere T : unmanaged
to existing APIs (which would otherwise throw at runtime) might be useful.public
members toprivate
orprotected
might be useful for hiding members that are too visible.TypeDescriptor
mechanism (which would make them extend to the whole application), or local solutions.Alternatives
extern partial
types and members which modify members of existing types. A similar syntax could be used for both, moving theextern partial
to the member itself (indicating that it is not a new extension member but an existing one):Examples
Nullability
Assembly A:
Assembly B, referencing A:
This adds nullability information to the existing members
C.S1
andC.S2
.Conditional execution
This stops calls to
Environment.Exit
from taking effect, unlessCAN_EXIT
is defined.Beta Was this translation helpful? Give feedback.
All reactions