Problem/Motivation
TraversableTypedDataInterface was introduced for code that needs to generically work with traversable typed data, specifically as a consolidation of commonalities between ListInterface and ComplexDataInterface.
A lot of code, however, does not utilize TraversableTypedDataInterface where appropriate, though.
Some of that is because TraversableTypedDataInterface doesn't provide the generic methods that it shoud.
Proposed resolution
Use TraversableTypedDataInterface wherever it makes sense. Specifically, this is wherever we are dealing with a parent typed data object of another object or where currently we still employ manual checks whether a certain object implements either ListInterface or ComplexDataInterface.
Move get() and isEmpty() up from ListInterface and ComplexDataInterface. These are not API changes.
There is one minor API change that is required, see below.
Remaining tasks
User interface changes
None.
API changes
Introduce a TraversableTypedDataDefinitionInterface with a getElementDefinition() method. This is the consolidation of ListDataDefinitionInterface::getItemDefinition() and ComplexDataDefinitionInterface::getPropertyDefinition(). I didn't remove the old methods to minimize API breakage. This means that only code that uses it's own data definition classes that don't subclass the core ones would break, which is very unlikely.
Beta phase evaluation
| Issue category | Task |
|---|---|
| Issue priority | Normal |
| Unfrozen changes | Not unfrozen |
| Prioritized changes | This is not a prioritized change for the beta phase. |
| Disruption | No disruption |
| Comment | File | Size | Author |
|---|---|---|---|
| #11 | 2420067-11-traversable-typed-data.patch | 26.19 KB | tstoeckler |
Comments
Comment #1
tstoecklerHere we go.
Had to introduce one minor API change to get this done properly, see the issue summary.
Comment #2
tstoecklerThe previous one missed the newly introduced
TraversableTypedDataDefinitionInterface. Same patch.Comment #5
tstoecklerI wanted to leave changes to the typed config system out of this patch as much as possible (and leave that to #2298687: Sequence and Mapping implement interfaces incorrectly, make them honest about what they support) but this change is necessary apparently.
Comment #7
tstoecklerConflicted on #2164601: Stop auto-creating FieldItems on mere reading of $entity->field[N]
Comment #9
tstoecklerDumb typo
Comment #11
tstoecklerLet's see what I messed up this time.
Comment #12
jose reyero commentedThis sounds like a good idea to me though I'm not that sure about changing the DataDefinition interfaces. We need also some clarification about what is a Property, what is an Item, what is an Element..
Also some methods that look the same are not actually the same, and I think this is a major DX issue that will be fixed by this patch:
Or also, this one that looks like trivial is very confusing.
Some handy links to follow this issue:
- ComplexDataInterface,
https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21TypedData...
- ListInterface,
https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21TypedData...
- DataDefinitionInterface hierarchy, https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21TypedData...
Comment #13
tstoecklerSo while I agree that they have slightly different semantics and we might not want to use them interchangeably in theory because of that...
...as the patch proves we already are! So, I think it makes sense to be true to ourselves and accept that we need these methods generically. We can certainly improve wording/documentation/... but...
Comment #14
jose reyero commented@tstoeckler,
Oh, no, what I mean is they must be fixed because having same method in similar interfaces with different semantics is really horrible, horrible DX. So we better consolidate all of them in TraversableTypedDataInterface.
So I'm 100% for this patch. I just mean it needs to be done carefully, looking at the different semantics and implementations and actually consolidating the behavior, not only the names of the methods.
One simple example: TraversableTypedDataInterface:get()
- The interface needs to specify exactly what happens (exception?) when we try to get a key that doesn't exist (for which there are two options, that it is not in the data and that it is not defined). Atm this is different for ComplexDataInterface and ListInterface.
TypedData is atm a major mess, and also lacking documentation everywhere about the purpose of each class and it should be fixed.
Comment #18
dawehnerIt is good to know that we have such an issue already!
Disclaimer: I have no idea about typed data.
Well, according to
https://secure.php.net/manual/it/class.traversable.phpthis is for stuff, that can be foreached. Do those things have anempty()function? Also an Iterator doesn't have the concept of random access/checking whether its empty. One question someone could ask is: What is the semantic information of traversable in typed data. For me at least, just by its naming, addingget()/empty()doesn't make sense necessarily.Comment #19
fagoI don't think this is something we should do. Reasons:
That said, the need for a comon parent interface for data containers is there. That should have a semantic meaning though and try to avoid introducing new terms that we have to learn/teach.
Lists and maps are different, I don't see why that makes a horrible DX when a list has items and a map has properties.
#1928868: Typed config incorrectly implements Typed Data interfaces shows that we miss proper support for an ordered, keyed collection of elements, having unknown keys. Maybe it would be best to just add dedicated supported for such a data structure? E.g., would the following make sense to you?
- DataContainer (parent data structure, no metadata nor API for fetching contained elements. Can have utility methods like isEmpty() or toArray())
|--- Complex Data (map with named properties)
|---- List (ordered list of items)
|---- Collection (ordered list of key,value pairs)
Complex data does not qualify as Collection, because the values are of a different type. (Depends on how you define "Collection" exactly). Given that, config schema sequences would be collections, which can be handled as lists also. (Thus the sub-type relationship).
Comment #20
fagoGiving the whole topic of data structures maps, collections etc. some more thoughts (once again), I figured the following:
- Collections are mostly considered as a very generic data structure, containing things like sets or trees. So it's probably not a good choice for "ordered list of key,value pairs", that's an ordered map.
- Map vs Complex Data and ordering: Our complex data does define whether it's considered ordered or not, what means you have to be able to work with either. Imo, it would be totally fine to have an implementation that is ordered.
But one thing we miss is the definition whether it may contain additional properties or not. E.g., json schema has that "additionalProperties" indicator for objects.
- A config schema sequence would be fine as ordered implementation of complex data, that allows additional properties (and has no metadata about pre-existing properties).
Comment #22
fago#2350597: Extract a common DataContainerInterface for lists and complex data is about to deprecated TraversableTypedDataInterface, so marking this as won't fix.
Comment #23
tstoecklerWow, that wasn't very nice. It's also pretty silly, because #2350597: Extract a common DataContainerInterface for lists and complex data will have to touch all the places that we would have cleaned up here anyway. So basically that one just increased its scope to swallow this one. Sigh...