Initializing Objects (Syntax)
Describe the feature
Initializing objects
@Max.Bauer
Author: Max BauerSub issues:
After a discussion within the LC-Types group, this was separated into sub issues:
- Default values in python syntax #220 (closed)
- Instantiating objects in less verbose python syntax #221 (closed)
- Issue of how to specify mandatory fields: #222 (closed)
Use Cases, which must be fulfilled:
To support all use cases and implementations of concrete scenario engines with and without with constraint solver we need a way to have:
- Default values
- Ability to randomize variables
- Specify required fields (which must be defined by users!)
The M-SDL proposal is not able to fulfil all use cases, as it is not possible to specify non optional fields. The following proposal tries to align all use cases with the syntax of the reference language Python.
The way of the reference language Python:
The following approach tries to combine all use cases in the style of the reference language python as much as possible. As a background the following site may be referenced, which demonstrates how python handles arguments: https://www.programiz.com/python-programming/function-argument
Python allows to define type signatures with default or non default arguments.
# This function takes the two arguments, both defined with some default value
def exampleFuncFullDefined(id: int = 0, some_string: string = "input_2"):
...
# This function takes the two arguments, one defined with default value
def exampleFuncPartlyDefined(id: int, some_string: string = "input_2"):
...
This way of defining functions is important, as it allows to specify functions arguments, which MUST be filled by the user.
# This can be called directly with arguments or without arguments -> both ways are valid
exampleFuncFullDefined(id = 0, some_string = "input_2")
exampleFuncFullDefined()
# This function must fail, if mandatory argument is not given
exampleFuncPartlyDefined(id = 0, some_string = "input_2")
exampleFuncPartlyDefined(id = 0)
exampleFuncPartlyDefined() # --> ERROR, id is mandatory to define id
...
Mapping the python syntax to OSC:
The python approach gives already the ability to express all previously mentioned use cases in the same manner. Furthermore it provides the benefit, that it is intuitive for the majority of the future users (as it is python syntax).
Functions:
Work the same way as in python.
Actions /Scenarios:
Actions/ Scenarios can be defined in a similar way. A default value can also be a randomize via constraints.
# This action takes the two arguments, one is randomized via constraints
action ActionA():
reference_vehicle: Vehicle = randomize() # default: randomize via constraint logic
direction: LaneChangeDirection = LaneChangeDirection::Right # default value
...
# This action takes the two arguments, one is randomized via constraints from a special list
action ActionB():
reference_vehicle: Vehicle = randomize(some_vehicle_list) # default: randomize from list
direction: LaneChangeDirection = randomize()
...
# This action takes the two arguments, one defined without default value (which must be defined now when called)
action ActionC():
reference_vehicle: Vehicle # <-- No default value, is mandatory to be initialized
direction: LaneChangeDirection = randomize()
...
This syntax now allows to fulfill all use cases:
- If defined with randomize, arguments can be randomized if they are not defined in the scenario call. They also can be randomized from a given list.
- Values can also be set with a default value which is always used, if not called from outside with other policy
- Values with non default values can be mandatory, which prevents calling them without setting this value explicitly
# This action is called and randomized, direction is in this concrete example set to default value
ActionA()
# This action can be also called with or without arguments, both ways are legit
ActionB()
ActionB(reference_vehicle = my_truck, direction = LaneChangeDirection::Left)
# This action can only be called if the mandatory field is defined, otherwise it is prohibited
ActionC(reference_vehicle = my_special_mercedes_car, direction = LaneChangeDirection::Left))
ActionC(reference_vehicle = my_bus)
ActionC() # --> ERROR,
Structs and Actors:
If we do not want additionally Constructors of classes, the same rule can be applied. Constructors could also be added in future versions.
# All fields are defined
struct MyFullyDefinedStruct
id: int = randomize(1..100)
my_bool: bool = true
pose: Pose = randomize()
dimension: Dimension = my_default_dimension
# Partly defined, the others must be given by the user explicitly
Actor MyPartlyDefinedActor
id: int
my_bool: bool
pose: Pose = randomize()
dimension: Dimension = my_default_dimension
As before, all use cases can be fulfilled with the python syntax:
# As the struct is defined fully, it can be called in python syntax in any way
my_struct = MyFullyDefinedStruct
my_specialized_struct = MyFullyDefinedStruct(id = 2, pose = map_xyz_mission_start_pose_12)
# This particular actor on the other side must be called with some explicit arguments
my_actor = MyPartlyDefinedActor(1, true)
my_actor_special = MyPartlyDefinedActor(id: 2, my_bool: true, dimension = mercedes_car_x_dimension)
my_actor_invalid = MyPartlyDefinedActor() --> ERROR, mandatory fields not given
Describe the solution you would like
Describe alternatives you have considered
I considered the M-SDL approach, but it lacks the following possibilities:
- Mandatory fields to set can not be expressed
- Default values can not be set (which differ from constraints!)
- Set Syntax differs from reference language python
However both concepts can be combined in a beneficial way, as they complement each other. The following example shows the python way of setting values (mandatory and default) AND additionally constraining values. The Constraints can be seen similar to asserts in python/C++
# Some fields are mandatory and some are default
struct OdrExplicitPoint
odr_id: int # Mandatory to be set by user
lane_id: int # Mandatory to be set by user
# If not set, choose as default something in this range (Default range is not equal to constraints!)
offset: distance = randomize(-1..1)
# Additionally we add constraints - We want this never to happen
keep(offset < 10)
keep(offset > -10)
# This allows now to call it the following way:
# distance will be randomized within default value bounds
point_1: OdrExplicitPoint(odr_id = 1, lane_id = 2)
# distance is set (outside of default range)
point_2: OdrExplicitPoint(odr_id = 1, lane_id = 2, distance = randomize(-2--2)
# ERROR: This is not possible, as it is a contradiction to the constraints
point_3: OdrExplicitPoint(odr_id = 1, lane_id = 2, distance = 2000)