Stream: shorthand
Topic: Array AutoIndexing status query
Kurt Allen (Jul 31 2020 at 19:35):
Hey @Chris Moesel @Mark Kramer
You talked about adding the capability to auto index arrays (reference last element, add new element, etc) recently. Do you still have plans to do this? Any guestimates on timing?
I am doing some funky stuff with arrays that would be easier if I didn't have to automatically increment automatic array indices. Hoping you did the work so I don't have to :-)
Mark Kramer (Jul 31 2020 at 19:37):
Hi Kurt, we are planning to Do something with this after the 1.0 release. We’d like to talk to you about ideas you might have associated with macros as a possible workaround.
Kurt Allen (Jul 31 2020 at 20:31):
Mark, here is what MFSH (Macro FSH) currently does.
Lets talk about this and see what parts make sense to move into FSH.
Macros
Macros are inserts with the following additions.
a) Named parameters.
When the macro is defined, named parameters are defined. When called, each of those
parameters must contain a value.
#macro XXYYZ(alpha, beta, delta)
#apply XXYYZ("alpha value", "beta value", "delta value")
Anywhere in the code that 'alpha' is found, it is replaced with 'alpha value'.
b) Global parameters.
There are parameters that are defined globally, such as
- the id of the current profile
- the url of the current profile.
- parameters that can be set on command line
many others
These can be referenced in any macro just as if it was a named parameter.
c) Redirection
The output of a macro can be redirected to a non-fsh file.
The output file name can contain global and named parameters which will get expanded when the macro is called/executed (not when it is
first defined)
I use this to collate info such as node graph commands I process externalluy to generate svg images, and also to allow embedded
macros to generate the --intro implementation guide files for each profile.
#macro XXYYZ() > 'redirection path'
d) Once flags
The once flag allows a macro to be called only once, even if it is executed multiple times.
Example of how this can be used:
Several macros are defined that add distinct sliced Observation.component items. These macros are sometimes used in a profile together, and
in some profiles separately.
Each macro calls a common macro to add component slicing; this should only be called once per profile.
One way to handle this is to force the user to call this macro separately, once per profile, but this requires the user to
manually add this and allows opportunities to not call it.
So a macro is defined that implements the required slicing commands, and it is called with the once flag set, so it
only generates FSH output the first time it is called.
There are two flavors of the once flag.
- restrict calls to once per profile
- restrict the calls to once period.
Named Parameters can be a problem here, as multiple calls can be made with difference named parameter values, and only
the first call will create output with its unique parameter values.
// this is expanded once per profile.
#macro once XXYYZ()
#end
// this is expanded once, no matter how many times it is called.
#apply once XXYYZ()
Fragments
A fragment is kinda a cross between a profile and a macro.
The purpose of a fragment is to define a profile fragment that
a) can be added to multiple profiles (like a macro)
b) is intended to signal to code generators that each fragment can be treated like a separate 'thing' (class or interface).
c) breaks the output profile into separate pieces that are functionally unique, implemented in multiple profiles, and documented as separate 'thing'.
Example.
I create a fragment 'f' that is three Observation.component items.
I include the fragment in multiple profiles 'a', 'b', and 'c'.
I generate a c# project that implements a class to process these profiles.
I can generate a method 'm' that can accept an interface 'f' that mimics the fragment 'f'.
Classes are created that mimic profiles 'a', 'b', and 'c', each of which implements interface 'f'.
I can call method 'm' with an instance of 'a', 'b', or 'c'.
So a fragment is a part of a profile that is to be implemented in multiple profiles but treated like a 'distinct' item
in generated artifacts (including implementation guide).
The fragment would have a parent class (like Observation).
It should generate an item in the implementation guide showing exactly what it implemented.
It should generate documentation in the documentation guide indicating what profiles implement it.
A profile can include one or more fragments just like a macro.
No named parameters are allowed in a fragment call.
The fragments generate structure definition and other meta data allowing external code generation tools to recognize
when a fragment has been defined, and where it is used. Programming artifacts can be generated from this info.
#Fragment: Observation.Component.NotPreviouslySeenFragment
#Parent: Observation
#Title: "NotPreviously Seen Fragment"
#Description: """
Adds NotPreviously Seen Component slice.
"""
#apply Observation.Component.Add("notPreviouslySeen", "0..*", "Not Previously Seen", "Not Previously Seen",
# """
# This slice contains the optional components that define prevous encounters in which this abnormality was not seen.
# The value of this component is a codeable concept chosen from the NotPreviouslySeenVS valueset.
# """,
# "ObservationComponentSliceCodesCS#notPreviouslySeen")
#
#apply Observation.Component.SetConcept("notPreviouslySeen", "1..1", "NotPreviouslySeenVS")
#end
Conditional compilation
This is completely experimental and I have not found it to be useful so far, but there may be instances where it may become useful.
This is identical to conditional compilation in c++, c3, etc.
We may want to ignore adding this to FSH. Not sure if it will ever be usefull, though we still need some way to implement
different countries using similar profiles.
i.e.
#if (value1=="true")
if value1 is true, then include all text here.
#else if (value2=="false")
if value1 is false, then include all text here.
#else
otherwise include all text here.
#end
The original purpose of conditional compilation was to allow a profile to be made that could be compiled for different countries.
i.e.
Profile: Hello
Parent: Observation
#if Country == "US"
-
greeting = "Hello"
#else if Country == "CA" -
greeting = "Hello, eh"
#else if Country == "NO" -
greeting = "Uff da"
#else if Country == "AU" -
greeting = "G'Day"
#end
Chris Moesel (Jul 31 2020 at 21:02):
@Kurt Allen -- for reference, here is a link to the discussion where we proposed an approach for easier management of arrays. If you read through the comments, you'll see it got some thumbs up, but there were also several people who did not like it: https://chat.fhir.org/#narrow/stream/215610-shorthand/topic/Feedback.20Needed.3A.20Array.20Syntax/near/203963085
Mark Kramer (Aug 10 2020 at 15:37):
I'm going to fork off a new topic on Parameterized RuleSet (Macros) so we keep the two conversations distinct.
Last updated: Apr 12 2022 at 19:14 UTC