cortoproject / corto

A hierarchical object store for connecting realtime machine data with web applications, historians & more
https://www.corto.io
MIT License
86 stars 14 forks source link

Create API for determining initializer order of members #683

Closed SanderMertens closed 6 years ago

SanderMertens commented 6 years ago

Corto serializers use corto definitions to determine in what order members are initialized when member names are not explicitly defined. For example, for the following type definition:

struct Point {
    x, y, z: int32
}

The following initializers are equivalent:

Point obj: 10, 20, 30
Point obj: x:10, y:20, z:30

Initializers can be nested, and styles can be mixed like so:

Line obj: start:(10, 20), stop:(x:30, y:40)

Things get more complicated when a user mixes using member-keys and implicit member values. A typical for this is when initializing a class with a base that implements an interface:

class Sub: my_base_class, implements:[my_interface] {...}

Which is equivalent to:

class Sub: base:my_base_class, implements:[my_interface] {...}

Things get even more complicated when a user is specifying members in a different order while using mixed notation. Another thing that complicates initializers is when a type uses inheritance and the base type uses the same member name as the sub type:

struct base_type {
   a, b: int32
}

struct sub_type: base_type {
    a, c: int32
}

When initializing a value of sub_type and explicitly specifying a, the outermost a (from sub_type) will be selected. To initialize a from base_type, the user has to add super:

sub_type obj: a:10, super.a:20 // sub_type/a = 10, base_type/a = 20

It is furthermore illegal to initialize a member twice in the same initializer, and initialize READONLY or PRIVATE members. HIDDEN members are not exposed when initializing without keys, but can be explicitly referred to with member keys. Alias members can pull members from a base class to a sub-class while hiding the other members from the base class.

Currently all of this logic is implemented in multiple ways across components (string serializer, cortoscript, code generators). It is easy to write code that covers 80% of the cases, but hard to cover all edge cases, which causes inconsistencies across components. To ensure consistency, this logic should be captured in a single API that is flexible enough to be used across components.

SanderMertens commented 6 years ago

Implemented - commits logged under #686