C# Futures: Static Delegates and Function Pointers
With each release of C#, it gains more low-level capabilities. While not useful to most business application developers, these features allow for high performance code suitable for graphics processing, machine learning, and mathematical packages.
In these next two proposals, we see new ways to reference and invoke functions.
A normal delegate in C# is a somewhat complex data structure. It contains a function pointer, an optional object reference for the this parameter, and a link to a chained delegate. The whole structure is heap-allocated like any other reference type, with the corresponding memory pressure. Furthermore, whenever it is used with unmanaged code it needs to be marshalled.
Compared to a normal delegate, a “static delegate” is greatly simplified. It is implemented as a struct with one field, a function pointer of type IntPtr. This makes it blittable, which means it has exactly the same memory layout when used in managed and unmanaged code. Or in other words, marshalling isn’t required when calling a native system function.
It is declared using this syntax:
static delegate int Func()
Additional settings such as character set and calling convention can be specified using an attribute similar to the UnmanagedFunctionPointer attribute .
Static delegates are not without limitations. They can only refer to static functions; member methods on objects are not permitted because there is no place to store the pointer to the object. Furthermore, static delegates cannot be chained to other delegates.
At the CLR level, a static delegate is invoked using the calli (call indirect) instruction. By contrast, a normal delegate is invoked using the call or callvirt (call virtual) instruction.
In order to make it more compatible with existing code, an implicit conversion from a static delegate to a normal delegate would be allowed. Going the other direction would require an explicit cast, as not all normal delegates meet the requirements of a static delegate.
You can read more about the Static Delegates proposal on GitHub.
A competing proposal is simply titled Function Pointers . This too exposes the ability to use the calli instruction and its partner, the ldftn (load method pointer) instruction. Like the previous proposal, it begins with a delegate declaration. Though in this case, the keyword delegate is replaced with funcptr.
funcptr int F1(int value);
When invoking a native function, the caller needs to know what the calling convention is. This affects things such as the order of items on the stack and whether the caller or callee is responsible for clearing the stack after use. The calling conventions covered by this proposal are cdecl, fastcall, stdcall, thiscall or winapi. The developer can specify which to use by modifying the delegate’s declaration:
funcptr cdecl int F1(int value);
In this proposal, function pointers would only be allowed in an unsafe context.
As part of this proposal you would be able to use the address-of operator (&) on a function’s name in order to create a function pointer. This too is only allowed to be used in an unsafe context.
The other restrictions on a function pointer are the same as a static delegate. Specifically, they can only refer to static functions and cannot be chained to other delegates.
Both proposals are under consideration and are not currently on the C# road map. A third proposal titled Compiler Intrinsics also competes with these two, but has additional limitations that make it less compelling.
Introduction I’m going to talk about “delegates” and “delegation.” I’ll lead you through a simple example of implementing the delegation design pattern in Object…
Long time no see dear readers and Appcoda fans! It’s been a long time since my last post here at Appcoda, and I am really glad to be back! Today, I’m going to discuss about an important and definitely interesting...
…wherein I talk a bit about how I’m doing dynamic memory management in C and C++ these days which basically replaces raw- and smart-pointers with ‘index-handles’. In mylast blog post I was mentioning pointer- an...
This summer, I am again working on Rust full-time , and again I will work (amongst other things) on a “memory model” for Rust/MIR. However, be...
Kubernetes is the market's leading open-source tool for automating deployment, scaling, and management of containerized applications. Most commonly, it's used with Docker containers. All major cloud providers have Kubern...
G Suite Pro Tip: how to create a dropdown list in Google Sheets (and p...
From HDR and editing tools to diagonal lines and more, we've got a host of smartphone photography tips you should check out.
In my work as a graduate student, I build distributed data structures, and having a remote pointer abstraction is an essential tool for me to write clean, correct code. In this blog post, I'll motivate why remote pointer...
futures_cpp - A future and stream library for modern C++.