Types
Problematic
Most (if not all) software projects use data. They need to structure it as well as validate it.
Information structure
All software projects structure its information. It is necessary to describe, manage and distribute it.
There is a lot of means to write this structure. Here some cases in different languages that could be found in projects:
Of course, each solution can be used in other languages and is not always representative of its developer community.
All of these solutions do the same thing: describe some information as a list of attributes. Some solutions are more verbose because of the language restrictions or conventions.
How could we see that these elements are data structures?
There is a list of attributes
All attributes are accessible from outside (directly or indirectly)
For each attribute, the same pattern appears: attribute definition, declaration inside constructor, getters and setters (when a pattern is inexistent, it is inexistent for all attribute)
So we have a common pattern. We could use for instance the version with the least characters to write.
Information validation
We looked at how to structure the information. For most of the structures, we can pass to the language syntax. However, there is another notion to look at.
Look at the following code:
What is the issue about this code? Should we consider this type valid as soon as we have two dates?
To ensure the data validation, we could do in several ways:
One more time, you can use some solutions in other languages.
It answers our question of how to validate data consistency. However, did you see that we check that start < end
and not that start <= end
? What happens if this restriction was added afterward and some data in your database are now invalid (where start == end
) but you need to accept the value for any reason? Your code and your data are not compatible anymore and will fail each time you query these values.
To avoid this case, you will surely define another function to deserialize data from your database and remove the validation. It is not an issue as long as you accept it. However, it creates some boilerplate that could be avoid.
Type syntax
Type declaration
You can declare a type by writing the following:
You can also give an alias to an existing type:
For more information about attribute declaration, please refer to part Attributes.
Verification reference
If you want to specify a verification that your type must validate, you can do it with a verification reference:
You can also do it with alias types:
Please see page Verifications for more information about using them.
Inline verification
If you want to define the verification inside the type, you can also do it:
Or with alias types:
Note that you do not need (and cannot) to give the type of the verification parameter. It is induced by the surrounding type.
Type parameters
If you want to declare parameters to your types in order to reuse their structure and logic, you can do it this way:
In concrete usage, top-level structures has few value to have type parameters. They mostly come in handy for alias types to increase the level of abstraction of common elements (NumberHigherThan
, ListOfSize
…).
Type verification parameters
You can also specify that you type verification need an external value. In this case, you will declare a named verification with parameters.
When you check the full aggregate of Order by using withConfiguration
, all verifications with this name will be included into the verification. So in above code, both withConfiguration
of Order
and OrderItem
will be call.
The top-level function in targeted language will require all parameters identified by their name. An error will occur if you use a name with different type in the same aggregate.
Type parameters or type verification parameters?
You could do what you want in both cases. However, these features were designed for two different cases:
Type parameters were designed for static invariants inside code, top-level aggregates should not have type parameters
Type verification parameters were designed for external parameters (configuration, user settings, options taken from an API…)
When you use one or the other, please think about where the value comes from and why you define this parameter.
Attributes
We talked about types but not their attributes specifically.
Attribute declaration
Their default usage is:
Attribute verifications
You can add verification references to attributes:
If you want to add a constraint to each tag, you need to define an alias type:
Also, if alias type has parameters, you can specify them:
Attribute usage
In the rest of the code, to access to an attribute, just name it:
All attributes are public and immutable.
Enumerations
Like most language, Definiti has an enumeration system.
You can describe them like:
Line returns are not required. You can also write the enumeration like:
You can compare enumeration values between them but you cannot use them another way.
Last updated