summaryrefslogtreecommitdiff
path: root/docs/proposals/004-com-support.md
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2024-09-05 15:12:52 -0700
committerGitHub <noreply@github.com>2024-09-05 15:12:52 -0700
commit5f1ba7b614b64d24fb45a3815a9867c68dace466 (patch)
tree40407853a5147e415ca3ad35ed03e1dadfb75cb1 /docs/proposals/004-com-support.md
parent313677160a186efebf83fab4df7d08dd119a5cd2 (diff)
Various documentation improvements. (#5017)
Diffstat (limited to 'docs/proposals/004-com-support.md')
-rw-r--r--docs/proposals/004-com-support.md240
1 files changed, 0 insertions, 240 deletions
diff --git a/docs/proposals/004-com-support.md b/docs/proposals/004-com-support.md
deleted file mode 100644
index dc0bd52d3..000000000
--- a/docs/proposals/004-com-support.md
+++ /dev/null
@@ -1,240 +0,0 @@
-COM Support
-===========
-
-When Slang is used as a host/CPU programming language, it is likely that users will want to use interact with COM interfaces, either by consuming them or implementing them.
-The Slang language and compiler should provide some first-class features to make working with COM interfaces feel lightweight and natural.
-
-Status
-------
-
-Implemented.
-
-Background
-----------
-
-COM is not perfect, but it is one of the only real solutions for cross-platform portable C++ APIs that care about binary compatibility and versioning.
-Developers who use Slang are likely to write code that uses COM, whether to interact with Slang itself (and/or GFX), or with platform APIs like D3D.
-
-While COM provides idioms for addressing many practical challenges, it is also inconvenient in that it introduces a lot of *boilerplate*:
-
-* COM types all need to implement the core `IUnknown` operations for casting/querying and reference counting.
-
-* Code using COM interfaces needs to perform `AddRef` and `Release` operations manually, or use smart pointer types to automate lifetime management.
-
-* Code that calls into COM interfaces typically needs to use boilerplate code and/or macros to deal with `HRESULT` error codes, handling or propagating them as needed.
-
-Our in-progress work on supporting CPU programming in Slang emphasizes supporting idiomatic code without a lot of boilerplate.
-Our intended path includes things that are compatible with the COM philosophy, like reference-counted lifetime management and idiomatic use of result/error codes, but those features don't currently align with the more explicit style used by COM in C/C++.
-
-Related Work
-------------
-
-The .NET platform includes some support for allowing .NET `interface`s and COM interfaces to interoperate.
-TODO: Need to study this and learn how it works.
-
-Proposed Approach
------------------
-
-We propose to allow COM interfaces to be declared using the Slang `interface` construct, with an appropriate attribute or modifier:
-
-```
-[COM] interface IDevice
-{
- ITexture createTexture(__read TextureDesc desc) throws HRESULT;
-
- void setTexture(int index, ITexture texture);
-}
-```
-
-A declaration like the above will translate into output C++ along the lines of:
-
-```
-struct IDevice : public IUnknown
-{
- virtual HRESULT SLANG_MCALL createTexture(TextureDesc const& desc, ITexture** _result) = 0;
-
- virtual void SLANG_MCALL setTexture(int index, ITexture* texture) = 0;
-};
-```
-
-Key things to note:
-
-* The `[COM] interface` becomes a C++ `struct` that inherits from `IUnknown`
-* Methods defined in the `[COM] interface` become pure-virtual `SLANG_MCALL` methods in C++
-* Parametes/values of a `[COM] interface` type `IFoo` in Slang translate to `IFoo*` in C++
-* Methods that have a `throws HRESULT` clause are transformed to have an `HRESULT` return type and an output parameter for their result
-
-A Slang `class` can declare that it implements zero or more `[COM] interface`s. Code like this:
-
-```
-class MyTexture : ITexture
-{
- // ...
-}
-
-class MyDevice : IDevice
-{
- ITexture createTexture(__read TextureDesc desc) throws HRESULT
- {
- return ...;
- }
-
- void setTexture(int index, ITexture texture)
- {
- ...;
- }
-}
-```
-
-translates into output C++ like this:
-
-```
-class MyTexture : public slang::Object, public ITexture
-{
- // ...
-};
-
-class MyDevice : public slang::Object, public IDevice
-{
- virtual HRESULT QueryInterface(REFIID riid, void **ppvObject) { ... }
- virtual ULONG AddRef() { ... }
- virtual ULONG Release() { ... }
-
- HRESULT createTexture(TextureDesc const& desc, ITexture** _result) SLANG_OVERRIDE
- {
- _result = ...;
- return S_OK;
- }
-
- void setTexture(int index, ITexture* texture) SLANG_OVERRIDE
- {
- ...
- }
-}
-```
-
-All Slang `class`es translate to C++ classes that inherit from `slang::Object` (equivalent to the `RefObject` type within the current Slang implementation).
-A `class` that inherits any `[COM]` interfaces includes an implementation of `IUnknown` plus the methods to override all the interface requirements.
-
-In ordinary code that makes use of `[COM] interface` types:
-
-```
-struct Stuff
-{
- ITexture t;
-}
-ITexture getTexture(Stuff stuff)
-{
- return stuff.t;
-}
-ITexture someOperations(IDevice device)
-{
- let t = device.createTexture(...);
- return t;
-}
-```
-
-the C++ output uses C++ smart-pointer types for local variables, `struct` fields, and function results:
-
-```
-struct Stuff
-{
- ComPtr<ITexture> t;
-};
-ComPtr<ITexture> getTexture(Stuff stuff)
-{
- return stuff.t;
-}
-HRESULT someOperations(IDevice* device, ComPtr<ITexture>& _result)
-{
- ComPtr<ITexture> t;
- HRESULT _err = device->createTexture(&t);
- if(_err < 0) return _err;
-
- _result = t;
- return 0;
-}
-```
-
-As a small optimization, an `in` parameter of a `[COM] interface` type translates as a C++ parameter of just the matching pointer type (see `device` above).
-
-Note that the translation of idiomatic `HRESULT` return codes into `throws HRESULT` functions in Slang allows code working with COM interfaces to benefit from the convenience of the Slang error handling model.
-
-
-Detailed Explanation
---------------------
-
-This is a case where the simple explanation above covers most of the interesting stuff.
-
-There are a lot of semantic checks we'd need/want to implement to make sure `[COM]` interfaces are used correctly:
-
-* Any `interface` that inherits from one or more other `[COM]` interfaces must itself be `[COM]`
-
-* Any concrete type that implements a `[COM]` interface must be a `class`
-
-There are also detailed implementation questions to be answered around the in-memory layout of `class` types that implement `[COM]` interfaces.
-In particular, we might want to be able to optimize for the case of a single-inheritance `class` hierarchy that mirrors a `[COM] interface` hierarchy, since this comes up often for COM-based APIs:
-
-```
-interface IBase { void baseFunc(); }
-interface IDerived : IBase { void derivedFunc(); }
-
-class BaseImpl : IBase { ... }
-class DerivedImpl : BaseImpl, IDerived { ... }
-```
-
-Using a naive translation to C++, the `DerivedImpl` type could end up with *three* different virtual function table (`vtbl`) pointers embedded in it: one for `slang::Object`, one for `IBase`, and one for `IDerived`.
-Clearly the `vtbl`s for `IBase` and `IDerived` could be shared, but C++ `class`es can't easily express this.
-Furthermore, if we are able to tune our strategy for layout, we can set things up so that `[COM] interface`s consume `vtbl` slots starting at index `0` and counting up, while any `virtual` methods in `class`es consume slots starting at index `-1` and counting *down*.
-Using such a layout strategy we can actually allow a type like `DerivedImpl` above to use only a *single* `vtbl` pointer.
-
-Questions
---------------
-
-### Should we emit COM code that works at the plain C level, or idiomatic C++?
-
-I honestly don't know. Emitting idomatic C++ (and using things like smart pointers) certainly makes the output code easier to understand.
-
-### Can we make this work with more advanced features of Slang interfaces?
-
-Some Slang features don't have perfect analogues. For example, given that `[COM] interface`s can only be conformed to by `class` types, the use of `[mutating]` isn't especially meaningful.
-
-There is no reason why a `[COM] interface` couldn't make use of `static` methods, but there would be no way to call those from C++ without an instance of the interface type.
-
-A `[COM] interface` could include `property` declarations, provided that we define the rules for how they translate into getter/setter operations in the generated output.
-
-One interesting case is that a `[COM] interface` could allow use of `This`, as well as `associatedtype`s that are themselves constrained by a `[COM] interface`.
-For example, we could instead device our `IDevice` interface from before as:
-
-```
-[COM] interface IDevice
-{
- associatedtype Texture : ITexture;
-
- Texture createTexture(__read TextureDesc desc) throws HRESULT;
-
- void setTexture(int index, Texture texture);
-}
-```
-
-We could set things up so that the `associatedtype` has no impact on the C++ translation of `IDevice`: all parameter/result types that use the `Texture` associated type would translate to `ITexture*` in C++.
-As such, a more refined `interface` like this would not disrupt the binary interface of a COM-based API, but could be allowed to express more of the constraints of the underlying API at compile time.
-For example, the above use of `associatedtype` would prevent Slang code from mixing up textures across devices:
-
-```
-void someFunc( IDevice a, IDevice b )
-{
- let x = a.createTexture(...);
- let y = b.createTexture(...);
-
- a.setTexture(0, y); // COMPILE TIME ERROR!
-}
-```
-
-In this example, `y` has type `b.Texture`, while `a.setTexture` expects an argument of type `a.Texture` (a distinct type, even if it also conforms to `ITexture`).
-The benefits of this approach are probably purely hypothetical until we make it a lot easier to work with dependent types like `a.Texture` in Slang code.
-
-Alternatives Considered
------------------------
-
-The main alternative would be to have Slang's model for interop with C/C++ focus primarily on C alone, and only allow use of COM-based APIs through C-compatible interfaces.