Introduction
Usage
This module is designed to be opened, like so:
open DkSDKFFIOCaml_Std
All modules introduced by the open
statement will start with Com
, like Com
, ComMessage
, etc.
The Com*
modules are explained in sections below.
First Things
Roughly speaking, COM objects are traditional objects (ex. Java, C++ and Swift objects) that have no class hierarchies but have "interfaces" similar to Java interfaces, pure C++ abstract classes and Swift protocols.
DkSDK COM objects live in an area of memory within a process that is separate from your programming language's objects. The key benefit of using COM objects is that they can be accessed by many programming languages.
Take for example Java and OCaml. If you need to have Java and OCaml interact in the same process, you could define:
- a "COM generic class" (defined formally in the next section)
- a Java proxy class that delegates to the COM generic class
- an OCaml proxy class that delegates to the COM generic class
You now have a bidirectional channel between Java and OCaml.
This may sound more involved than a traditional FFI (Java JNA, OCaml ctypes, etc). It is! But you gain portability of your code between languages; the same OCaml code can work in an Android (Java) application, and the same OCaml code can work in an iOS (Swift) application, and the same OCaml code can run natively in a desktop application.
And what you write is simpler than you may initially think:
- Often you don't need a bidirectional channel: just make a Java proxy class and skip the OCaml proxy class when you have an OCaml callback function that you need to access from Java.
- Most of the programming details to "delegate" from a programming language to the COM generic class are auto-generated for you.
The most primitive concepts you will need to understand are COM interfaces and COM objects:
- A COM interface is a uniquely identifiable type representing a set of functions that manipulate a COM object, which is a uniquely identifiable value that may hold state in memory. The convention is that a COM object can only be manipulated through COM interface functions. Each function is numbered within an interface, unlike conventional functions which are named. The first three functions are reserved to be:
- The first function, commonly called "QueryInterface", is responsible for finding other interfaces.
- The second and third functions, commonly called "AddRef" and "Release", are responsible for implementing manual reference counting. Manual reference counting is the technique used so that COM objects know when to free up their memory.
In DkSDK FFI, you primarily interact with two COM interfaces.
The COM generic class object is a value that:
- has a set of "class" methods. Each class method accepts a single Cap n' Proto "Struct" message and returns a single Cap n' Proto "Struct" message. Think of Cap n' Proto as a highly efficient form of a JSON message; its full documentation is available at the Cap n' Proto website. There is a Struct message type called ComObject that can be returned to represent new COM objects.
- has an "interface" (defined below) that has the same fully qualified name as the class
- is conventionally represented in OCaml as a module
The COM generic instance object is a value that:
- has state stored in RAM memory
- has a set of "instance" methods that can manipulate that state. Each instance method accepts a single Cap n' Proto "Struct" message and returns a single Cap n' Proto "Struct" message. The Struct message type ComObject can be returned to represent new COM objects.
- has an "interface" (defined below) that has the same fully qualified name as the COM class that defined the set of instance methods
- has a set of interfaces that the instance object can be downcast to
- is conventionally represented in OCaml as an object that can be downcast using the OCaml
:>
"coercion" operator
The COM generic interface is a type which is a specialization of the COM interface. A generic interface is the set of all future and existing COM generic objects that both:
- have the same set of generic class and instance methods
- is uniquely identified by the fully qualified COM class name that defined the set of methods
The module Com
is where you can get pre-existing COM generic class objects and call methods on COM objects.
Messages
Each host platform has a different Cap n' Proto message signature. These differences encapsulate the different ways the host platforms manage memory. Some host platforms use manual memory management, some use the type system, some use referencing counting and others use full garbage collection. Regardless, the Cap n' Proto message signature hides all of the host language memory management details.
Schemas
Any Cap n' Proto schema can be used for sending and receiving messages through DkSDK FFI.
A set of single-element structures is available for convenience when you don't want to generate your own Cap n' Proto schema. All of the basic scalar Cap n' Proto types are available as single-element structures.
In addition, the ComStandardSchema.S.Reader.ComObject
and ComStandardSchema.S.Builder.ComObject
types are used to pass back and forth references to DkSDK COM objects. Its schema is the ComObject schema.
Persistence and Transmission
Serialization and deserialization protocols.