-
Notifications
You must be signed in to change notification settings - Fork 204
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to interpret inheritance with and without @discriminator #2450
Comments
|
Let me ask more directly - Do we have any implicit information the Cat is not allowed for that method in above example from TypeSpec point of view? |
After talking with @MaryGao offline, I'll clarify a few things. From a pure typespec point of view the example above is totally correct and an operation would allow a If we think for example of typespec as a way to generate typescript interfaces(Or any other language) but that doesn't involve any serialization then there is no reason this shouldn't be allowed. An example of this use case is generation of the decorators typescript types form the typespec definition. But as pointed in previous reply as soon as serialization is involved you are not able to deserialize the |
For tsp, it is valid. But I don't think it is valid for http. There is no good to write this but will involve lots of problems including ser/deser problem. |
I have what is possibly a comparable interpretation, though I'm not entirely sure. Sharing in case it helps. From my perspective, ignoring decorators, I would not expect an emitter or serializer to handle subclasses of a base class given an operation like The fix to this interpretation is to be specific. Again in the absence of any decorators, that would mean doing something like: As far as I'm concerned, the fact that adding |
Maybe I misunderstood, but can we treat inheritance and polymorphism two different things? Inheritance is just reuse some of the the base class stuff like properties methods, which means there's no way to call a subclass method via a baseclass pointers, in those scenarios, base class are just normal class. In this case, when we get an object of subclass, it's depends on whether we can accept additional properties for this base class instead of from an inheritance perspective to serialize or deserialize it. but if we want to change the runtime or compile behavior according to the type. in this case, we could use a base class pointers to call a sub class method, we have to specify discriminator to indicate there's a polymorphism here, which means in the above case,
we got an operation here |
Service team leverages typespec to express their backend contract, regarding the above statement If this is a general question for all services then emitter could follow that, if it is a case-by-case decision then emitter could do nothing.
It looks like magic to me. @Discriminator is not just pointing discriminator property but like a syntax sugar. It seems that below two cases are equivalent in typespec.
|
I consider them separate from an API definition standpoint, but they cannot be separated for all emit targets where inheritance implies polymorphism. But I think this is fine.
I believe that is the intention of the @discriminator-on-base-class, but is the behavior I'm skeptical about and would prefer being explicit with unions.
IMO the contract is simply that the service will take a Pet and may or may not support additional properties depending on convention we prefer. The default position would be that subtypes are allowed as that aligns with the TypeSpec type system's semantics, and in general, I believe services often do accept additional properties, so any subtype of Pet would be allowed, not just those that happen to be declared in the TypeSpec (@johanste has talked to me about this before, maybe he knows more). But in either case, I don't think the presence of subclasses should affect what this code means (in the absence of @Discriminator at least).
They are equivalent from a type system perspective yes (and I strongly prefer the latter), however @Discriminator on the union is still useful for codegen because we don't need to infer what the discriminator is and we can ensure the discriminator is present on all union members as the API evolves. So I prefer this pattern:
We have also discussed allowing union to express a subtyping relationship such that all union variants must be a subtype of the specified type, so Pet could be defined as:
This effectively prevents random other types that happen to have a "kind" field from being added to the union. |
Note that there is an issue around how we should encourage types using extends in Azure APIs to use discriminators here: https://github.com/Azure/typespec-azure/issues/3510 |
closing a sduplicate |
Say we have inheritance case without discriminator decorator(playground). We have
Pet
as request body increate
operation. I was wondering how to interpret this in the semantic:Pet
andCat
orDog
? Or just the composization relationship due Cat contains all properties of Pet?Cat
orDog
as valid parameter in operationcreate
?The same questions are for enabling the decorator
@discriminator("kind")
. AreCat
orDog
valid parameters in operationcreate
?The text was updated successfully, but these errors were encountered: