-
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?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
# Unmanaged constant types | ||
|
||
* [x] Proposed | ||
* [ ] Prototype: [Complete](https://github.com/PROTOTYPE_OWNER/roslyn/BRANCH_NAME) | ||
* [ ] Implementation: [In Progress](https://github.com/dotnet/roslyn/BRANCH_NAME) | ||
* [ ] Specification: [Not Started](pr/1) | ||
|
||
## 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 commentThe reason will be displayed to describe this comment to others. Learn more. C# notably doesn't have a concept of |
||
|
||
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 commentThe reason will be displayed to describe this comment to others. Learn more. There's potential issues with regards to variable length types such as |
||
|
||
It could be expanded to include any `readonly struct` type. | ||
|
||
We should consider if a `ref struct` type, such as `ReadOnlySpan<T>` could be a compile-time constant. | ||
|
||
## 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 commentThe reason will be displayed to describe this comment to others. Learn more. Expanding the notion of |
||
|
||
Similarly, any other type that holds multiple values, like record struct types, could be used to match patterns. For example, a `Point` type could be matched agains a `const` for the origin. | ||
|
||
Other uses for constant expressions include: | ||
|
||
- default argument values. | ||
- Attribute parameters | ||
|
||
## Detailed design | ||
[design]: #detailed-design | ||
|
||
This is the bulk of the proposal. Explain the design in enough detail for somebody familiar with the language to understand, and for somebody familiar with the compiler to implement, and include examples of how the feature is used. This section can start out light before the prototyping phase but should get into specifics and corner-cases as the feature is iteratively designed and implemented. | ||
|
||
## Drawbacks | ||
[drawbacks]: #drawbacks | ||
|
||
Why should we *not* do this? | ||
|
||
## Alternatives | ||
[alternatives]: #alternatives | ||
|
||
What other designs have been considered? What is the impact of not doing this? | ||
|
||
## Unresolved questions | ||
[unresolved]: #unresolved-questions | ||
|
||
What parts of the design are still undecided? | ||
|
||
- What types should be allowed? | ||
- What are the implications of allowing constant ref structs? Are they even useful? | ||
- How will down-level scenarios work? Can these constants be accessed by code using previous compilers? What about using Reflection to access fields? | ||
- 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 commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. C# already diverges from the runtime's concept of constants. Consider const decimal d = 1.0M; Results in:
Plus a static ctor to assign that value. |
||
## Design meetings | ||
|
||
Link to design notes that affect this proposal, and describe in one sentence for each what changes they led to. | ||
|
||
|
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