-
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
Adding the static-delegate proposal. #126
Changes from 2 commits
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,74 @@ | ||
# Static Delegates | ||
|
||
* [x] Proposed | ||
* [ ] Prototype: Not Started | ||
* [ ] Implementation: Not Started | ||
* [ ] Specification: Not Started | ||
|
||
## Summary | ||
[summary]: #summary | ||
|
||
Provide a general-purpose, lightweight callback capability to the C# language. | ||
|
||
## Motivation | ||
[motivation]: #motivation | ||
|
||
Today, users have the ability to create callbacks using the `System.Delegate` type. However, these are fairly heavyweight (such as requiring a heap allocation and always having handling for chaining callbacks together). | ||
|
||
Additionally, `System.Delegate` does not provide the best interop with unmanaged function pointers, namely due being non-blittable and requiring marshalling anytime it crosses the managed/unmanaged boundary. | ||
|
||
With a few minor tweaks, we could provide a new type of delegate that is lightweight, general-purpose, and interops well with native code. | ||
|
||
## Detailed design | ||
[design]: #detailed-design | ||
|
||
One would declare a static delegate via the following: | ||
|
||
```C# | ||
static delegate int Func() | ||
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. Bikeshed: 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. @alrz, static delegates can only refer to static methods. This is because delegates which refer to instance method also require you to carry a reference to the 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. Also, maybe 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. I prefer The In this case it's a delegate that can only refer to 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. What about open delegates? Delegate.CreateDelegate would probably not work with this. Will there an API to create an open static delegate that directly points to a member of the input parameter? 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. I'm confident that this document correctly reflects the current (very preliminary) state of the proposal. We can discuss possible changes to it in the linked issue. |
||
``` | ||
|
||
One could additionally attribute the declaration with something similar to `System.Runtime.InteropServices.UnmanagedFunctionPointer` so that the calling convention, string marshalling, and set last error behavior can be controlled. NOTE: Using `System.Runtime.InteropServices.UnmanagedFunctionPointer` itself will not work, as it is only usable on Delegates. | ||
|
||
The declaration would get translated into an internal representation by the compiler that is similar to the following | ||
|
||
```C# | ||
struct <name> | ||
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. The 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. I put a placeholder here because I think just 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. Changed the placeholder and provided a text explanation/example. |
||
{ | ||
IntPtr pFunction; | ||
|
||
static int Func(); | ||
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. The name here should be a standard name used across all static function types. That way the compiler knows what name to look for when determining the signature. Not sure if that's going too far or not for the language spec though as it's a bit of implementation detail of the compiler. 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. I'm not sure either. @MadsTorgersen or @gafter, how should we represent placeholder data like this? 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. I updated this to be WellKnownCompilerName for the time being and added a text description indicating as such. |
||
} | ||
``` | ||
|
||
That is to say, it is internally represented by a struct that has a single member of type `IntPtr` (such a struct is blittable and does not incur any heap allocations). The member contains the address of the function that is to be the callback. Additionally, the type declares a method matching the method signature of the callback. | ||
|
||
The value of the static delegate can only be bound to a static method that matches the signature of the callback. | ||
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. For better interop with unmanaged code, it might be desirable to allow assigning the value of a static delegate to that of an However, given that the static delegate type is itself blittable, the only scenario this would improve is if you had an unmanaged function that returned a As such, I left that off the proposal. |
||
|
||
Chaining callbacks together is not supported. | ||
|
||
Invocation of the callback would be implemented by the `calli` instruction. | ||
|
||
|
||
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. double blank line. 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. Removed. |
||
## Drawbacks | ||
[drawbacks]: #drawbacks | ||
|
||
Static Delegates would not work with existing APIs that use regular delegates (one would need to wrap said static delegate in a regular delegate of the same signature). | ||
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. It is probably worth noting that 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. This incompatibility could be addressed though. The language could allow an implicit conversion from any 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. Yes, which is why I called it out here. I will add a note to the proposal indicating that we could workaround this. 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. Note added. |
||
|
||
Additional work would be needed to make Static Delegate readily usable in the core framework. | ||
|
||
## Alternatives | ||
[alternatives]: #alternatives | ||
|
||
TBD | ||
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# does not currently provide any mechanism to expose the 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. Yep. |
||
|
||
## Unresolved questions | ||
[unresolved]: #unresolved-questions | ||
|
||
What parts of the design are still TBD? | ||
|
||
## 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.
What is this mark down trick doing?
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.
It allows you to link to the sub-section of the document (this is based on the proposal-template.md).