Stream: implementers
Topic: Structure Definition
Chris Grenz (Apr 07 2016 at 15:13):
Quick ? - only HL7 can use StructureDefintion.derivation = specialization, correct? @Michel Rutten What are you doing with this in Forge?
Michel Rutten (Apr 07 2016 at 15:18):
@Chris Grenz Forge is still based on FHIR DSTU2, whereas StructureDefinition.derivation was introduced in DSTU3. For new profiles, Forge currently initializes StructureDefinition.constrainedType to the selected base resource type.
Michel Rutten (Apr 07 2016 at 15:19):
specialization seems intended for logical models (and core resources?)
Chris Grenz (Apr 07 2016 at 15:20):
Seems like there's a lot of churn in that part of the SD with changed in kind/type/contextType etc.
Chris Grenz (Apr 07 2016 at 15:20):
I'm struggling a bit to keep my tooling current! Right now, we're supporting 0.5, 1.0.x, and (soon) 1.4.
Michel Rutten (Apr 07 2016 at 15:20):
Yes, we discussed some of these changes in Atlanta. in STU3 it should be more regular.
Chris Grenz (Apr 07 2016 at 15:21):
Must've missed that discussion...
Michel Rutten (Apr 07 2016 at 15:21):
We will upgrade all our tools (incl. Forge) to STU3 after the Montreal balloting rounds. Until then, we will stick to DSTU2.
Chris Grenz (Apr 07 2016 at 15:22):
Also, really struggling with the benefit of elementdefintion.base. What was the motivation there?
Michel Rutten (Apr 07 2016 at 15:22):
It allows tooling to quickly determine the original path of the associated base element.
Chris Grenz (Apr 07 2016 at 15:24):
When would base.path != path?
Michel Rutten (Apr 07 2016 at 15:24):
And cardinality, e.g. if base resource defines an element as 0...* then a code generator would generate a List property. If a derived profile constrains the element to 0..1, then a code generator would still need to generate a List property, in order for the derived class to be compatible with the base class. The ElementDefinition.base component specifically solves this problem.
Michel Rutten (Apr 07 2016 at 15:24):
e.g. for choice elements, base path ends with "value[x]" where actual path ends with "valueString".
Chris Grenz (Apr 07 2016 at 15:24):
OK...nice for XML to JSON for sure. That could just be a single flag though...
Chris Grenz (Apr 07 2016 at 15:25):
So path="valueString" and base.path = "value[x]"?
Michel Rutten (Apr 07 2016 at 15:25):
This information could be calculated by resolving the base resource profile or expanding the snapshot, but this is a costly operation.
Michel Rutten (Apr 07 2016 at 15:25):
e.g. path = "Observation.value[x]", base.path = "Observation.valueString"
Chris Grenz (Apr 07 2016 at 15:26):
Does base just go back one generation, or all the way back to the first appearance of the element?
Michel Rutten (Apr 07 2016 at 15:26):
In Forge, I currently initialize all the element base components while opening/loading the resource. This ensures that other business logic can safely assume the information is present and correct.
Michel Rutten (Apr 07 2016 at 15:27):
Good question... I'd have to think about that. I assume element.base refers to the path in the root profile, but I'm not sure - need to carefully look at an example.
Chris Grenz (Apr 07 2016 at 15:28):
So Patient baseDefinition of Acme-Patient baseDefinition of Acme-Neuro-Patient.
- Acme-Patient has path = "Patient.deceasedDatetime" (base.path = "Patient.deceased[x]")
- Acme-Neuro-Patient as path="Patient.deceasedDatetime" for further constraint. What is base.path?
Michel Rutten (Apr 07 2016 at 15:28):
According to the description, element.base.path always refers to a core structuredefinition without a StructureDefinition.base component.
Michel Rutten (Apr 07 2016 at 15:29):
ElementDefinition.base.path: "The Path that identifies the base element - this matches the ElementDefinition.path for that element. Across FHIR, there is only one base definition of any element - that is, an element definition on a StructureDefinition without a StructureDefinition.base."
Michel Rutten (Apr 07 2016 at 15:29):
So Acme-Neuro-Patient has the same base.path = "Patient.deceased[x]"
Chris Grenz (Apr 07 2016 at 15:29):
OK...so the "most base" element definition. And element[x] is always "more base" than elementType.
Chris Grenz (Apr 07 2016 at 15:29):
ok...fair enough!
Michel Rutten (Apr 07 2016 at 15:29):
This makes sense, as this is the information that is useful in application logic.
Chris Grenz (Apr 07 2016 at 15:30):
thanks!
Michel Rutten (Apr 07 2016 at 15:32):
np. FHIR should be crystal clear on these concepts, so it's important we discuss this.
Chris Grenz (Apr 07 2016 at 15:33):
Part of this is that there's getting to be some mental "inertia" for some of us! "Now what happened there?" frequently crosses my mind!
Grahame Grieve (Apr 11 2016 at 05:20):
base is really useful if a structure definition profiles a data type inline - just walks straight into it
Grahame Grieve (Apr 11 2016 at 05:21):
path = Observation.valueQuantity.unit, base = Quantity.unit
Grahame Grieve (Apr 11 2016 at 05:21):
It's on my task list to write up how the FHIR typing system works formally for the current build.
Grahame Grieve (Apr 11 2016 at 05:21):
or we can work through it when I come visit you ;-)
Chris Grenz (May 17 2016 at 17:49):
Right now, I think the general understanding is that snapshot and differential should be calculable from each other (round trip-able). Maybe should be a little clearer on this. Consider the need for a profiler to define a profile that includes only a particular set of extensions from an enterprise set (the profile uses the enterprise profile as its baseDefintion). For instance, a cardio service may define a profile of encounter that uses 5 of the 25 extensions defined by the enterprise.
Question is: how does the profiler enforce the limitation of only 5 extensions (not cardinality, 5 urls)? He can close the slicing and max=0 the 20 to be disallowed. But if/when the enterprise defines the 26th, it will appear in the cardio profile.
IF we allow definition by snapshot, it would be possible to explicitly limit the slices that appear, but the machinery gets a little wonky (snapshot is always a superset of all elements/sliced defined in the baseDefinition lineage). Is there a mechanism to meet this use case I'm missing?
Grahame Grieve (May 17 2016 at 19:38):
if you allow 5 and close, then why does it matter if another is defined somewhere else?
Chris Grenz (May 17 2016 at 19:38):
If it's added to your baseDefinition, you'll (forcibly) inherit it.
Grahame Grieve (May 17 2016 at 19:39):
why? you said, these 5, and closed it.
Chris Grenz (May 17 2016 at 20:50):
The base has extension.slicing.rule="open" and defines 25 extensions. My profile closes the extensions (extension.slicing.rule="closed") and max=0 all the ones I want to exclude. But if another appears in the base (the 26th), it will already be part of my closed slicing (by inheritance). There's no way to block that...
Michel Rutten (May 19 2016 at 14:40):
@Chris Grenz how about if the derived profile defines another extension slice with max = 0 and no url property. Since the extension slice discriminator is always the url (per definition), this "catch-all" constraint would match any remaining extensions that do not match any of the other extension slices, at least conceptually. If this constraint then specifies max = 0, it would explicitly suppress any implicitly inherited extensions from the base profile not matched by any of the other slices. Do you think this could work?
Chris Grenz (May 19 2016 at 14:43):
Yes, that would work. Do we state what happens when a discriminator isn't set? I think it should work as you describe...
Chris Grenz (May 19 2016 at 18:33):
@Michel Rutten maybe not now that I think about it. Only _one_ slice may apply to any instance. I don't think this means that a "catch all" is valid since both the catch all and the specific version would apply to an instance with a related slice definition. In other words, an extension slice with no fixedUri for @url would apply to all extension instances and therefore disallow any other slices.
Chris Grenz (May 19 2016 at 18:34):
What you *could* do though would be to define a type profile of extension where max=0 for the url element. But that would require slicing extension by @profile and not url.
Chris Grenz (May 19 2016 at 18:34):
And the discriminator for extension is fixed to url.
Michel Rutten (May 20 2016 at 11:34):
@Chris Grenz yes, that seems to be correct. My suggestion would require a change to the standard, in order to define the proposed interpretation and behavior as such. I was just thinking out loud about how to cover your use case. Your suggestion of using a type profile might also work, but slicing by profile can be (very) computationally intensive and might not be supported by many FHIR servers. So personally, I consider this to be an advanced technique that you should use only if there are not simple alternative ways to express the intended constraints.
Michel Rutten (May 20 2016 at 11:40):
Seems like the expressive power of SlicingRules are too limited to express the desired constraints of your use case. It somewhat resembles binding strength, through wich a profile author can limit binding overrides in a derived profile. Maybe we can expand the SlicingRules?
Chris Grenz (May 20 2016 at 13:42):
(deleted)
Chris Grenz (May 20 2016 at 13:43):
Would really like to come up with a way to express this without a major breaking change....
Chris Grenz (May 20 2016 at 13:53):
I may be that what I'm trying to do breaks the concept of polymorphic inheritance and shouldn't actually be allowed. There's no way in most object oriented languages for a sub-type to constrain changes on the super-type or, more precisely, for the sub-type to selectively decide what to inherit from the super-type.
Chris Grenz (May 20 2016 at 13:53):
But that's not exactly how the FHIR type system works either....
Chris Grenz (May 20 2016 at 13:55):
I like your suggestion of a "everything else" slice...a notation for that might be the least disruptive.
Chris Grenz (May 20 2016 at 13:56):
It makes parsing somewhat harder though since all other slices have to be exhausted before it would match...similar to evaluating the "closed" rule.
Chris Grenz (May 20 2016 at 13:57):
Sorry for the rambling....that won't actually work either since the slices actually *are* defined in the baseDefinition and would just inherit intact.
Michel Rutten (May 20 2016 at 15:15):
Hmm... you always come up with these interesting cases ;p I definitely agree that it is preferred to find a compatible solution that doesn't introduce any breaking changes. Just having a hard time to find one. In this case, if I understand correctly, you need to suppress the inheritance of (yet) unknown information from the base profile. However SliningRule = closed on your derived profile only applies to profiles that derive from the derived profile, i.e. downstream 3rd+ level profiles. It does not lImit the inheritance from the original base profile and therefore cannot protect against future additions to the base profile, right? Hence my feeling that in order to express this behavior, we might have to expand SlicingRule with yet another option, e.g. sealed or something.
Chris Grenz (May 20 2016 at 16:58):
The primary issue is that we define by differential. We can only define how the profile is different from the base. So, we'd need to be able to re-generalize base specializations, e.g. create a slice that encompasses a set (an open ended set!) of base slices. While my use case is real, it really feels like an architecturally unsound thing to do within the profile hierarchy.
Chris Grenz (May 20 2016 at 17:02):
An alternate might be a profile that requires conformance to another profile but doesn't inherit from it. Unfortunately I think I accidentally removed this possibility with GF#9814 when we removed type from the root element. While I don't *think* anyone was enforcing this, it would have been possible for a profile to set type.profile on the root element and therefore force conformance with another profile.
Chris Grenz (May 20 2016 at 17:04):
With this, I could create a profile that required conformance to anther profile (e.g. an enterprise Patient profile) without using that as a base.
Michel Rutten (May 23 2016 at 14:18):
@Chris Grenz There has been some discussion on supporting (the union of) multiple profiles. I specifically remember that Claude Nanjo would has requested support for this functionality. The idea being that instead of having a single-inheritance chain of profiles, you can combine/overlay/aggregate multiple separate profiles into one. This would allow a more composition-based / aspect-oriented profiling approach. However because of the complexity and calculation costs, we haven't even started to implement any of this (yet...). Note that in Forge, the element type profile textbox actually allows you to enter multiple profile urls (press enter to add another line), however Forge currently only validates the first type profile and ignores any remaining type profiles. And Grahame informed me that he is not about to implement support for this in his server.
Chris Grenz (May 23 2016 at 14:30):
I've thought about multiple inheritance as well and found it to be as distasteful as it was in programming languages. I would differentiate though between multiple inheritance and additional conformance constraints: each profile must only inherit from one profile, but they could state conformance to other profiles. This wouldn't cause the other profiles' content to be included. It would just state an additional (complex) constraint.
Grahame Grieve (May 23 2016 at 21:00):
we can calculate whether a profile is a constraint on another or whether it's consistent with another
Chris Grenz (May 23 2016 at 21:02):
Yes, but we can't use another profile as a constraint (such as we can do with individual element type profiles) to the whole profiled type.
Grahame Grieve (May 23 2016 at 21:12):
the first is - all instances that conform t profile A conform to profile B
Grahame Grieve (May 23 2016 at 21:12):
the second is - there are some instances that conform to both profiles
Grahame Grieve (May 23 2016 at 21:12):
agree that we should only try to deal with one explicit parent
Chris Grenz (May 23 2016 at 21:13):
So if I define an "Enterprise Patient" profile, could I (without inheriting from it) say that a conformant resource MUST also be DAF-Patient conformant?
Grahame Grieve (May 23 2016 at 21:15):
yes, by explicitly requiring that in your meta.profile. but not implicitly no
PS (Feb 11 2020 at 04:28):
How can we pass our own structure definition(In JSON or XML) to Hl7.Fhir.Specification (.net package provided by fire.ly) so that it can validate against the object?
Thanks
Grahame Grieve (Feb 11 2020 at 05:31):
you might get a quicker answer if you post this question to #dotnet
PS (Feb 11 2020 at 05:46):
Will do. Thanks
Radha Rajendran (Apr 08 2021 at 09:52):
Hello all,
Can anyone please share structure definition examples with minValue and maxValue ?
These fields are choice of datatype, so could not find the exact key name for this fields .
Lloyd McKenzie (Apr 08 2021 at 15:27):
Already asked and answered here: https://chat.fhir.org/#narrow/stream/179166-implementers/topic/StructureDefinition.20.20and.20unknown.20properties
Last updated: Apr 12 2022 at 19:14 UTC