I'd like to propose some modifications of your suggestion and present it a bit differently. Also let's keep in mind that the same notation would apply to get_attribute.
This is going to be purposely verbose because I want to take you along for the traversal ride! But I think in the end it's quite intuitive.
Since we're moving to a traversal notation, then I think we can do away with "SELF". It should be assumed that we start with ego. Specifically, though, there are a few possibilities for the starting point entity:
(The "instance" is very important here when we think of get_attribute, because while properties are the same across all instances, attributes are not.)
We determine which entity according to where the function call is located. Note that this location applies to both "templates" (node_templates, groups, policies, relationship_templates) and to types (node_type, group_type, etc.), such as the "default" keyword in the type.
OK, so that's our starting point. We then have a few options for the first step. I do want to point out that all subsequent steps might traverse us to a set of instances rather than a single instance. I'll explain more about that when we get there.
Also note that if we are traversing as a set, the result of the get_property functional call will be an array of results. This doesn't matter if there is one result, many results, or no results (empty array).
SUBSEQUENT STEPS
OK, so now we have a few additional options.
The previous step may have traversed us into a property (or attribute in the case of get_attribute) value. If that's the case we can stop here. Or, if the value is complex, we can continue moving deeper into the value's structure in subsequent steps. So we can use:
- Field names (the "properties" of a complex data type)
- Map keys
- List index (an unsigned integer)
(Side note: What happens if we don't continue traversing into a complex value? Would the entire value be returned? The format for that would differ per parser/orchestrator implementation, which would be OK. But this is something that the spec does not discuss.)
We can also use the various keywords mentioned in the first step to continue traversing, according to what kind of entity we are at right now: CAPABILITY, ARTIFACT, RELATIONSHIPS, NODES, SOURCE, TARGET.
However, it's important to understand that if we are traversing as a set, there is no turning back to traversing a single path. All subsequent steps would be sets.
For example, let's consider a simple example of traversing as a set, where the starting point is a group instance:
get_property: [ NODE, CAPABILITY, mycap, myprop ]
We might have 10 node templates in the group, so we are traversing as a set. And then we are gathering all the capabilities named "mycap" from all of those nodes. And finally we are gathering all capability properties name "myprop" from all those node instance capabilities.
A more complex example from the same starting point of the group instance:
get_property: [ NODE, RELATIONSHIPS, myreq, TARGET, CAPABILITY, mycap, myprop, mylist, 1 ]
The 10 node templates in the group would have 10 or more or less relationships named "myreq" (it could be less if the "occurrences" range was [0,UNBOUNDED] and the requirement was not specified in one of the node templates), so step #2 might increase/decrease the size of the set as we move to a set of relationships. Step #3 would move us to the relationship targets, but since each relationship has one target the size of the set would be the same as in step #2, now comprising nodes again. Step #4 moves us to capabilities, again the same size (there's only one capability of that name per node). And finally we'll get the result as an array of all those capability properties, and so on.
DISCUSSION OF IMPLICATIONS
The move from traversing singularly to traversing as a set is subtle. Because it amounts to a different kind of function call result, it may make sense to break it into two functions to increase clarity:
- get_properties: This is for traversal as sets. The assumption is that we always start as a set (with one member, our starting point in instance) and always return an array of values.
- get_property: This is for singular traversal and will always return a single value. This means that any traversal keyword that would move us to traversing as a set would not be allowed. Looking above, this is exactly two keywords: RELATIONSHIPS and NODES. (Those are the two keywords expressed in plural form, to emphasize the fact that they move us to a set.)
Is it too complicated to chose between two functions? A few other options:
We could possibly just have the plural function, get_properties. The advantage is that the "traversal as a set" distinction doesn't have to be considered. The problem is that in some situations we really do expect and need a single result, even if there are many potential results.
So another thing we can do is keep both get_properties and get_property, the former returning an array and the latter returning a single result. However, we do not restrict the latter from traversing sets (RELATIONSHIPS and NODES keywords). Instead, we specify that if there are multiple results then an arbitrary one is selected. This could "just work" as expected in some trivial situation, but the indeterminacy is frightening.
Finally, let's look at get_attribute. If you've been following the discussion until now you'll realize that we should always traverse as a set. The reason is that even if we stop at a node template entity, we would have to gather the attributes from all instances. So for consistency there should be a get_attributes function but no get_attribute function, because we should always expect multiple results.
Another interesting implication: if we use get_attribute where the starting point is a policy instance, then we have to traverse to somewhere else. The reason is simple: nodes, groups, and relationships all have attributes, but policies do not.
I have some more thoughts about notation but will stop here, because I think there's quite enough to discuss.
In case we do want to discuss in meeting, please note that I am unable to attend the meeting next week on Sep 24! But you can go on without me. :)