-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Start proposal for more constant types #8257
base: main
Are you sure you want to change the base?
Conversation
This proposal includes changing the runtime to understand and support for more types in attribute parameters? Would that also include the pseudoconstant |
I love it! |
## Summary | ||
[summary]: #summary | ||
|
||
Expand the allowable types for compile-time constants (`const` declarations) to any value type that is fully blittable. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
C# notably doesn't have a concept of blittable
, only unmanaged
. blittable
has a specific meaning, as it pertains to interop
, and types like bool
aren't considered blittable
unless the user opts-in via DisableRuntimeMarshalling
@@ -0,0 +1,79 @@ | |||
# Unmanaged constant types |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a similar proposal, from 2017, that goes over a different approach to supporting this functionality here: #688
|
||
The current specification [§12.23](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1223-constant-expressions) limits constant expressions to an enumerated set of types, or default reference expressions (`default`, or `null`). | ||
|
||
This proposal expands the types allowed. The allowed types should include any unmanaged type ([§8.8](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/types.md#88-unmanaged-types)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's potential issues with regards to variable length types such as nint
or nuint
where today the underlying primitive constants are restricted to their 32-bit domain
public object SomeReference; | ||
} | ||
``` | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do we reconcile this with the runtime concept of field constant?
Currently C# constants match the runtime's version of field constants. For example, a field can be declared that is a constant which is different than a static field with a value. The constant value is encoded in the metadata which the compiler uses to emit as load instructions at the use site instead of referencing the field at runtime, because no field exists for it at runtime. The kinds of values that can be field constants is constrained to those that can be encoded in metadata. I'm not sure what those are, but it probably does not include arbitrary types even if they are blittable.
Of course, C# could deviate from the runtime and allow other types to be constant but would have to change to use static fields for these instead of field constants.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
C# already diverges from the runtime's concept of constants. Consider decimal
:
const decimal d = 1.0M;
Results in:
// Fields
.field public static initonly valuetype [System.Runtime]System.Decimal d
.custom instance void [System.Runtime]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, uint8, uint32, uint32, uint32) = (
01 00 01 00 00 00 00 00 00 00 00 00 0a 00 00 00
00 00
)
Plus a static ctor to assign that value.
- **What types should be allowed?**: Preventing mutation for types whose members are all unmanaged types (or `struct` types whose members are all unmanaged types) is a manageable problem: a `const` instance can't be accessed as a writable `ref`. However, if any member is a reference type, that problem is harder to solve. | ||
- **Are there implications for the runtime?** Depending on how constants are stored in memory, is there an impact on the runtime? | ||
- **What are the implications of allowing constant ref structs? Are they even useful?**: Are the rules surrounding ref safety consistent with where constants are used? | ||
- **How will down-level scenarios work?** Can these constants be accessed by code using previous compilers? What about using Reflection to access fields? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we should make sure that reflection handles these new constant types. Our users expect reflection to return C# constants as properly typed values (dotnet/runtime#104270 (comment) has some discussion about issues we have in this area currently.)
## Motivation | ||
[motivation]: #motivation | ||
|
||
Only constant expressions can be used in pattern matching expressions. This expands the types that can be used in patterns. For example, it's common to use GUIDs as identifiers. This feature enables matching on GUID values. Currently, the only way to do that is to convert a GUID to a ReadOnlySpan<byte> and use a list pattern on the list of bytes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expanding the notion of const
in the language is a decent sized feature as it ends up touching on a number of areas. If the main motivation is to expand the set of types usable in patterns should we just approach that more directly?
- **Does a type need to "opt in" to all constant definitions?** (Otherwise, changes later could introduce a field that disallows all existing `const` declarations): | ||
|
||
```csharp | ||
public struct Point | ||
{ | ||
public int X; | ||
public int Y; | ||
} | ||
|
||
// V2: | ||
|
||
public struct Point | ||
{ | ||
public int X; | ||
public int Y; | ||
public object SomeReference; | ||
} | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First draft at a proposal to enable more types to be declared as
const
types.