Stream: hapi
Topic: Common attributes across resources
James Agnew (May 12 2016 at 14:20):
Hi All, so a proposal came to me from @Bryn Rhodes via @Grahame Grieve:
There's actually a common set of elements across all resources - identifier, code, url, date, etc
If we make every resource implement that interface, and then we can generate the accessors for each resource, based on meta data defined in the resource definitions (I have a slot for that)
My immediate reaction is that this could be convenient, but would also be problematic. My main concern is that you lose some of the benefit of static type checking. E.g. if Patient
now has a method getCode()
even though the patient resource has no such property, I might accidentally call patient.getCode()
and I'm presumably now getting a runtime error instead of a compile time one.
One possible mitigation of this would be to split the proposal into a few interfaces. IHasCode
, IHasIdentifier
etc, and have the individual resources implement those. Another option might be to deprecate the methods on the resources that aren't used.
Thoughts?
(Pinging @Ewout Kramer @Brian Postlethwaite for their thoughts from the .NET side)
Grahame Grieve (May 12 2016 at 15:24):
my immediate response is that IHasCode is just moving the deck chairs around. Yes, this will create run time errors. But this is mainly useful when you have a object of type "Resource" anyway, and wahtever you do is going to be run-time error anyway
Grahame Grieve (May 12 2016 at 15:24):
if thing instanceof [type] then ...
else
runtime error....
Grahame Grieve (May 12 2016 at 15:25):
so I don't think that's persausive
Michael Lawley (May 12 2016 at 19:18):
I would certainly help implementers of Terminology Services where all our key Resources have common elements.
FWIW, my first thought for mitigating the issue of unwanted methods on other Resources was also your suggestion of marking them as deprecated. Reasonable, I think, from a Java perspective, but would this need to flow across into all language bindings?
Grahame Grieve (May 12 2016 at 20:18):
I don't follow the deprecation argument, So you deprecate the implementation - so what
James Agnew (May 12 2016 at 20:48):
The idea there is that if you are putting getCode()
on the Resource
class, you could put a copy of it on Patient
that is marked as deprecated so that users get a compile-time warning if they try to use it on Patient.
The more I think about it though, I'm not clear on what problem this solves. Does this method throw an exception if you call it incorrectly? (say, getCode()
on Patient
) If so, you need to test for instanceof
before you call it anyhow so you could cast it then...
Grahame Grieve (May 12 2016 at 20:52):
ok you want a deprecation so as not to use it directly - I follow that
Grahame Grieve (May 12 2016 at 20:53):
I would return null - there is no code on patient. Since the intent is that you use it generically, it's not an error to call it on patient, there just isn't one.
James Agnew (May 12 2016 at 20:56):
Ugh, I don't like that at all... That's a recipe for bugs. I guess this is my general problem with this, the whole intent we have with HAPI at least is to provide as much compile-time checking as possible for code. That's why we use annotated fields for extensions for instance.
Would it make more sense to just provide a utility class with a method List<CodeableConcept> getCode(Resource theResource);
Grahame Grieve (May 12 2016 at 20:56):
you can't have an implementation with a lower visibility can you?
James Agnew (May 12 2016 at 20:56):
sadly not
Grahame Grieve (May 12 2016 at 20:56):
really, I don't understand why that's better than just putting it on an interface
Grahame Grieve (May 12 2016 at 20:57):
what's the practical difference between resource.getCode() and Utilities.getCode(resource) other than ungainly syntax?
James Agnew (May 12 2016 at 21:02):
well, to me the practical difference is that there are no misleading methods showing up in intellisense on Patient.java this way. If I use the utility method it's clear that I need to be careful.
To be honest though, I still don't understand why this whole thing is useful. What are the situations where you don't care what type of resource you have, you just want its code or identifier. Are they common enough that they merit "polluting" the resource hierarchy for convenience? That's what I'm trying to weigh...
Grahame Grieve (May 12 2016 at 21:04):
common properties on the conformance resource - which will be spreading to more CQI resources. Identifier. .... perhaps status.... And a bunch of things that are a datatype ModelMetaData that will be flattened on the various resources it lives on
Grahame Grieve (May 12 2016 at 21:05):
I constantly use .getUrl(), .getStatus(), .getDate(), .getName() on conformance resources generically
Grahame Grieve (May 12 2016 at 21:05):
Bryn does too
Grahame Grieve (May 12 2016 at 21:07):
I would not put .getCode on there - this is not something that is remotely consistent across resources
James Agnew (May 12 2016 at 21:09):
On a related note, I've heard complaints now from a few developers that the DSTU3 structures have pages and pages of "castToFoo" methods showing up in intellisense. I do see value in being kind to people who work that way..
But surely we wouldn't add something like getUrl()
to Resource just for your/Bryn's conformance use cases? If a bunch of the conformance resources all have these properties, should we just have a BaseConformanceResorce class that all of them inherit from that adds the 4 properties you list?
Grahame Grieve (May 12 2016 at 21:21):
well, maybe we could, yes, though I'm not sure where I'd drive it from.
Grahame Grieve (May 12 2016 at 21:22):
can we do something clever with the cast* methods, or is it all or nothing?
Josh Mandel (May 12 2016 at 21:36):
I'm kind of worried that we're inventing a whole alternative approach to inheritance with this interfacey-view-layer thing.
Grahame Grieve (May 12 2016 at 21:37):
well, we are extremely limited in our approach to inheritence. Further, we often do not use it because not all features of an element are common, even when the parts related to code generation are constant
Grahame Grieve (May 12 2016 at 21:38):
but i suppose that rather than interfaces, I could optimise the generation to use inheritence carefully
Grahame Grieve (May 12 2016 at 21:38):
James, how would you feel about introducing a new abstract resource "ConformanceResource"
James Agnew (May 12 2016 at 21:39):
I would feel very good about that approach
Josh Mandel (May 12 2016 at 21:39):
:-)
Grahame Grieve (May 12 2016 at 21:40):
@Bryn Rhodes - I think that this comes to the same outcome, and I think it works for you
Grahame Grieve (May 12 2016 at 21:42):
James, the getXType methods - I use these a lot so I love them but I know that they clutter the hints
James Agnew (May 12 2016 at 21:43):
Yeah, I understand that... I don't see an easy solution to that, and at least they are grouped together.
Grahame Grieve (May 12 2016 at 21:45):
can't see any way to suppress them
James Agnew (May 12 2016 at 21:46):
I'd say let's leave them alone then.
Bryn Rhodes (May 12 2016 at 22:05):
So are we saying that there would be a BaseConformanceResource type that all the conformance and artifact-related resources would descend from, and we would flatten the ModuleMetadata type into elements on that resource?
Grahame Grieve (May 12 2016 at 22:06):
maybe. Or another base resource instead - depending on how the resources are changed
Bryn Rhodes (May 12 2016 at 22:08):
That makes sense and addresses the use case.
Grahame Grieve (May 12 2016 at 22:22):
ok. I'll do that. james, do you need to do something in HAPI if I do that?
James Agnew (May 12 2016 at 22:26):
Nope, just let me know when it's ready and I'll sync the structures into HAPI
Grahame Grieve (May 12 2016 at 22:29):
ok I'll let you know
Brian Postlethwaite (May 13 2016 at 04:08):
On the IHasCode interface stuff, my 2c is that there are probably a couple of groups of resources that could have a common interface like that IConformanceResource (with the URL etc params), IPatientRelatedResource (with patient, identifiers ...)
Grahame Grieve (May 13 2016 at 07:57):
that's what we decided to do
Grahame Grieve (May 13 2016 at 07:58):
@Ewout Kramer @Brian Postlethwaite would you do the same in C# if I defined the semantics in a mapping in the structure definition?
Brian Postlethwaite (May 13 2016 at 12:30):
Do you mean generate the baseconformance resource?
Grahame Grieve (May 13 2016 at 12:31):
yes.
Brian Postlethwaite (May 13 2016 at 12:32):
If so then yes could do that
Brian Postlethwaite (May 13 2016 at 12:32):
Ok.
Grahame Grieve (May 13 2016 at 12:32):
great.
Brian Postlethwaite (May 13 2016 at 12:37):
With dot net we'd use extension methods for the little used stuff in a special namespace for those that want them.
This reduces stuff in intelligence. Don't know if there is an equivalent in java
James Agnew (May 13 2016 at 23:15):
nope :(
Last updated: Apr 12 2022 at 19:14 UTC