DTDL - Data Type Definition Language
The Data Type Definition Language is used to describe data types used in a schema of foster.
DTDL allows to define classes, lists and structs. Objects inside DataFS contain one or more classes. Lists and structs
are used as multi value attributes.
The following sections describe the basic elements of the language.
Comments
You can write comments in the files in the C++ format.
// Comment Type 1
/* Command Type 2 */
class
A class has a unique global id and attributes.
If a class does not have a body, then it's called an "external" class. These classes can be used
for linking.
class
Type1
[ id({DA249990-6D74-496E-B06A-C0694033665E}) ]
{
int32
value1;
wstring
value2;
double
value2 [v]; // variable attribute
};
struct
... same as class, but the struct is packed into a single binary block and stored in one single attribute.
list
... same as struct. But the items first 16 bytes must be unique. You can use the option 'custom key' if your
application can guarantee the uniqueness itself.
list
SampleList [ id({BA506E95-D20C-4E9A-8960-2210E7E46F87}), ck ] // ck for "custom key"
{
object
link; // unique 16 bytes
wstring
strName;
};
list
SampleList
[ id({BA506E95-D20C-4E9A-8960-2210E7E46F88}) ]
{
int
value;
};
Preprocessor
The language uses to types of preprocessor commands. The #include and #use. They both load an external file.
While #include imports the file and all definitions inside completely, the #use command imports all definitions
as external definitions.
The difference between the </> and "/" format is how the file is searched. While " takes the current file
as starting point, </> takes the input directories passed to the compiler as starting point for the search.
#include
<file.dtdl>
#include
"..\directory\file.dtdl"
Inheritance
Classes, lists and structs can inherit from one or more types. In this case the action of the compiler
can be seen as copy-paste of the inherited types into the inheriting type.
Namespaces
DTDL supports namespaces. There are different possibilities to define namespaces. Either using the
way known from C++, a shorter way or by simply putting the namespace name in front of the name of a new type.
namespace
a
{
namespace
b
{
class
q
; // defines a::b::q
}
}
namespace
a::b
{
class
q
; // defines a::b::q
}
class
a::b::q
; // defines a::b::q
Description
You can place a description in front of a definition. This description will be stored in the schema and
can be seen as documentation.
[ this is an empty class ]
class
q
{};
Data types
Type | Description |
int8 | 8 bit signed integer |
uint8 | 8 bit unsigned integer |
int16 | 16 bit signed integer |
uint16 | 16 bit unsigned integer |
int32 | 32 bit signed integer |
uint32 | 32 bit unsigned integer |
int64 | 64 bit signed integer |
uint64 | 64 bit unsigned integer |
int128 | 128 bit signed integer |
uint128 | 128 bit unsigned integer |
int256 | 256 bit signed integer |
uint256 | 256 bit unsigned integer |
float | 32 bit float |
double | 64 bit float |
char | 1 byte character |
wchar | 2 byte character |
datetime | FILETIME |
string | 1 byte character string |
wstring | UTF-16 string |
guid | GUID |
variant | VARIANT |
bsob[size] | binary small object of size 1 to 127 bytes |
blob | - currently not supported - |
stream | - currently not supported - |
object | object (an object id or a reference) |
Object Types
For values of type 'object' you can specify a set of classes you expect the objects to have when
linked by this value. The system does not guarantee that object have all of those classes or restrict
operations that cause a violation of these rules.
objecttype
a::b::q
.val_obj(type_t
); // attribute 'val_obj' of type q in namespace a::b should contain class 'type_t'