-
Notifications
You must be signed in to change notification settings - Fork 227
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
Improve mixin documentation + possibly mixin bug #2535
Comments
Using the following Smithy definition in a file called $version: "2.0"
namespace com.example
@mixin
map MyMixin {
/// Generic docs
key: String
/// Generic docs
value: String
}
map MyMap with [MyMixin] {}
apply MyMap$key @documentation("Specific docs")
apply MyMap$value @documentation("Specific docs") Running {
"smithy": "2.0",
"shapes": {
"com.example#MyMap": {
"type": "map",
"mixins": [
{
"target": "com.example#MyMixin"
}
]
},
"com.example#MyMap$key": {
"type": "apply",
"traits": {
"smithy.api#documentation": "Specific docs"
}
},
"com.example#MyMap$value": {
"type": "apply",
"traits": {
"smithy.api#documentation": "Specific docs"
}
},
"com.example#MyMixin": {
"type": "map",
"key": {
"target": "smithy.api#String",
"traits": {
"smithy.api#documentation": "Generic docs"
}
},
"value": {
"target": "smithy.api#String",
"traits": {
"smithy.api#documentation": "Generic docs"
}
},
"traits": {
"smithy.api#mixin": {}
}
}
}
} Running {
"smithy": "2.0",
"shapes": {
"com.example#MyMap": {
"type": "map",
"key": {
"target": "smithy.api#String",
"traits": {
"smithy.api#documentation": "Specific docs"
}
},
"value": {
"target": "smithy.api#String",
"traits": {
"smithy.api#documentation": "Specific docs"
}
}
}
}
} These are the outputs I would expect and do not match with what you're reporting. What version are you using ( |
I think there is a misunderstanding. The bug report is for this example:
It produces a json that has an apply shape for Valid$a to apply the required trait, but the A2 structure already has the required trait applied to the member shape already. The description for the example says "Traits applied to redefined members supersede any traits inherited from mixins." but that is not really demonstrated. |
Map, list, and union examples should be added to the docs as an enhancement. |
Mixins can be used with any shape, and the rules for how they work are the same across each of them for traits and members. Non-member properties are called out later on that page since they're not quite so straight-forward. If you're writing your own AST logic that consumes models from
Ah, I see, sorry for the mixup! That particular example is intended to showcase that the target shape is the same, and thus new traits may be applied. Apply statements are used any time a trait is applied to an existing member, whether that's via another mixin or via a local definition. Apply statements are used here instead of redefining members on structures because apply statements are more resilient to change over time if the shapes targeted by an inherited member changes. |
I'm sorry, I still don't understand what you're saying. Why is there both an apply shape for Valid$a to apply the required trait, and also the required trait on the A2 structure? I would assume one or the other but not both. If this is to demonstrate the precedence, it's not clear either. |
the tl;dr that this is to solve a different problem, we can't tell the difference once we get to writing out the ast, and since behaviorally there's no difference there's no need to. Apply statements are added for any introduced traits, however or wherever they were introduced. Think of this as the equivalent of the // foo.smithy
$version: "2.0"
namespace example.foo
@mixin
structure Foo {
spam: String
} // bar.smithy
$version: "2.0"
namespace example.bar
use example.foo#Foo
structure Bar with [Foo] {
@required
$spam
} Now imagine that on some day the target of That syntax is functionally the same thing as using the Now back to the specific example you've cited. It's different in that the introduced trait was introduced from another mixin rather than locally, so why is that apply statement there? The answer is that it's a minor performance tradeoff. If we had to check this case, we'd have to check it for every mixin. But if we don't, then we only have extra checks in the specific case where two non-hierarchical mixins define the same member, which is ultimately not that common. If there were behavioral differences, this would be a problem we'd of course have to fix. But there isn't a distinction, there's just an effective noop apply during model loading.
This is not to demonstrate precedence, there's an example for that earlier on in the page. |
That makes sense. It sounds like there's just a documentation improvement here. Do as you will. |
There are a few more improvements that can be made to the mixin documentation.
This states
Members that are mixed into shapes MAY be redefined if and only if each redefined member targets the same shape. Traits applied to redefined members supersede any traits inherited from mixins.
however the example below does not demonstrate that redefined members supersede any traits. The example would be stronger if it used a trait with a property that gets overridden.This is a possible bug with the example from 1). If you run
smithy ast
on the example above, it produces a json that has an apply shape for Valid$a to apply the required trait, but the A2 structure already has the required trait applied to the member shape already.Mixins can also be applied to maps, lists, and unions. Are there any other aggregate cases? It would be great to include examples of these. In my generator, I used the examples from this page to test that mixins get resolved by our model traversal logic. It did not handle these cases. A minimal example for Map might be:
The text was updated successfully, but these errors were encountered: