-
Notifications
You must be signed in to change notification settings - Fork 208
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
Implementextends
base type for union
#2737
Comments
For a typical extensible string (open enum that could have more value than specified), is it now be below? union OpenEnum extends string {
"type1",
"type2",
@unknownVariant
string,
} I am not sure what type is the @disciminator("kind")
union Type extends {"kind": string} {
Type1,
Type2,
@unknownVariant
UnknownType,
}
model UnknownType {
"kind": string,
...Record<unknown>,
} (I wrote |
What we have today will still work and should still work. I don't think simple primitive unions should need to have For the 2nd part I think it could be either:
@disciminator("kind")
union Type extends PetBase {
Cat
Dog,
@unknownVariant
PetBase,
}
model PetBase {
"kind": string,
}
@disciminator("kind")
union Type extends PetBase {
Cat,
Dog,
@unknownVariant
UnknownPet,
}
model PetBase {
"kind": string,
}
model UnknownPet {
"kind": string,
...Record<unknown>;
} I think it is up to the spec writer to decide what they rather do. And maybe in Azure we need to agree on a standard way of doing this. |
Part of SDK's concern is version resiliency. E.g. if we have this in v1 @resource
model Resource {
type: "type1" | "type2"
} On paper, we are sure the "type" be only "type1" or "type2". However, if "type3" is added to v2, it would be hard to say that v1 SDK accessing that resource won't have "type=type3" as return (the resource would be returned, the "type" is required property so some value had to be in it). I assume the recommendation of Union Type extends string {
"type1",
"type2"
} to Azure service is based on this. |
BTW, does Union OperationStatus extends string {
"Running",
"Succeeded",
"Failure"
}
Union ServiceOperationStatus extends string {
OperationStatus,
"NotStarted"
} |
Just to not mix things, So those 2 should not be producing anything different
an extensible union will still need to have that extra variant that define extensiblity, in the case of string it would be either of those
for this I believe yes this should work
|
est: 5 |
Additional DiscussionIn the above discussion, the following union
Some language emitters would prefer to make the inclusion of To enable this extra constraint, we could add a core decorator In the above
|
Another option: admit @willmtemple was right and use |
|
Using
This become a little separate issues from this one which just adds constrains to the union. So we should just implement the original proposal with Separate issue to discuss:
|
extends
base type for unionextends
base type for union
est: 5 |
Goals
Extends clause for unions
Sometimes, an API may want to constrain a union's to all share a particular subtype. For example, this constraint allows for some languages to represent unions with a polymorphic base type. The need to express this relationship led to the undesirable pattern of applying
@discriminator
on a base model, where references to the base model either refer to that model or to a union of its subtypes depending on context. This pattern is not ideal for a number of reasons, and expressing the model-side relationship between super- and sub-types separately from the union of subtypes that might be present for a given API is generally preferred.However, this presents two problems for where we're at today:
To address these problems, we can add an
extends
clause to unions like so:From a TypeSpec semantics perspective, the
extends
type does not imply any subclassing relationship but merely documents a constraint that the union is a subtype of the given extends type, and thus that each of its variants are as well. When this constraint is violated, a diagnostic is given on the offending variant.The extends type will show up in the type graph, giving emitters a convenient way to know if the union's variants share a common base type that can be used as a polymorphic base. It is not recommended for emitters to require this constraint to be present however, and should ideally handle a union with the same variants with or without the constraint in a similar way. In particular, the presence of an extends clause does not indicate that the union is "extensible", and has no new interaction with the
@discriminator
decorator.The extends clause is an expression that matches the grammar of an extends constraint on a template parameter.
Change to the default behavior of named unions
Today, a named union is (I believe?) emitted identically to an unnamed union for most languages.
Extensible Unions
Extensible unions are unions where the set of union variants is not known, and so clients and servers need to handle unknown variants. In some cases, the unknown variant is a supertype of the other variants, in which case we might want a feature like
sealed classes
which allow subclasses to opt out of additional properties. In other cases, the unknown variant may be a special variant that is unrelated to the others.In either case, the union should include the unknown variant, and we need a way for emitters to identify the unknown variant. There are a few options:
The drawbacks of each:
I think a decorator on the variant,
@unknownVariant
, is the best option, and in the future we can consider a keyword.The text was updated successfully, but these errors were encountered: