Migrating to Coco Standard 1.2¶
The Coco Language standard 1.2 includes several features that have required backwards-incompatible changes to be made to the language and also the generated code. These will require users to manually alter their code in order to use their existing models with the new language standard.
Coco¶
With standard = 1.2
there are several names that are now keywords:
monitor
;trace
.
Further, there are several names that cannot be used as the name of a member of a port:
ambiguous
drainQueue
end
start
send
timer
unused
When upgrading, conflicting declarations will need to be renamed. It will be easiest to do this before setting
standard = 1.2
, as that way Coco’s semantically-aware renaming can be used. One potential workflow would be to
briefly set standard = 1.2
and make a note of all files that have errors in them. Then switch back to
standard = 1.1
and modify all previously noted errors.
With standard = 1.2
, the default value of logValues
has changed from Never
to
WhenAvailable
. This means that values will be logged by default. This has several implications:
- The generated logging data will have a different format, so if you have tools that read the log files these may need to be modified.
- The generated code will require the runtime logger to support logging values. The loggers that are shipped as part of
the Coco runtime will support this out-of-the box (e.g. for C++, :icpp:`coco::StreamMachineLogger`), but if you are
using a custom logger implementation you may need to upgrade this to support logging values, or alternatively you can
set
logValues
toNever
.
Generated C¶
The generated C code includes one small change when generator.c.style
is set to ObjectOrientated
: there is
now an explicit destroy function that must be invoked to cleanup any memory allocated by the component.
For example, typically the Coco generated C code will be used as follows:
System component;
System_create(&component);
System_coco_start(&component);
// use component
With standard = 1.2
, once the component has been terminated and is no longer required, the corresponding destroy
method should be used to cleanup all allocated memory:
System_destroy(&component);
Generated C++¶
The generated C++ code now uses a slightly different method to generate C++ code for tagged enums (i.e. enums with data). This change was necessary to support using C++’s partial template specialisation feature on tagged enums.
This change only affects users who manually interacted with Coco’s tagged enums from C++, which is only likely if there are external functions or external components in Coco that have parameters that are of tagged enum types. This is not that common.
Previously, the generated C++ code for a tagged enum might look like the following:
struct MyCocoEnum {
struct EnumCase1_ {
bool x;
};
struct EnumCase2_ {
bool x;
};
using type = coco::variant<EnumCase1_, EnumCase2_>;
type EnumCase1() { … }
type EnumCase2() { … }
};
With standard = 1.2
, this will be modified so that the MyCocoEnum
type is the referred-to type. This is done by
adding a member to MyCocoEnum
that stores the variant:
struct MyCocoEnum {
struct EnumCase1_ {
bool x;
};
struct EnumCase2_ {
bool x;
};
using type = coco::variant<EnumCase1_, EnumCase2_>;
MyCocoEnum EnumCase1() { … }
MyCocoEnum EnumCase2() { … }
type storage;
};
Further, any member functions of MyCocoEnum
declared in Coco
will be member functions on the new MyCocoEnum
C++
struct.
The following need to be made to hand-written user code (note that C++ code generated by Coco will be automatically converted - these changes only apply to hand-written code):
- Any C++ type that refers to
MyCocoEnum::type
will need to be changed to justMyCocoEnum
. - Any uses of
coco::get
will need to be modified to use the innerstorage
member. For example,coco::get<T>(x)
should be modified tococo::get<T>(x.storage)
. - Any uses of the member function
index
will need to be modified to use the innerstorage
member. For example,x.index()
should be modified tox.storage.index()
. - Any uses of user-defined member functions on the Coco-defined enum will need to be modified to be member function
calls instead. For example
someFn(x)
would becomex.someFn()
.