-
Notifications
You must be signed in to change notification settings - Fork 144
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
Runtime error with "properly generated needle code" #456
Comments
Yes, as you noticed When we initially came up with the API, we thought about using comments so that the you could just tell us who the children of a particular components were. We decided that comments were prone to typos and such, so we decide to go with the current pattern where a parent component must instantiate it's children somewhere in the body to let needle know about parent -> child relationships. |
Yeah, I wasn't sure how easy it would be to use the AST to figure it all out properly. I did have an interesting thought for a way to resolve the issue with Instead of trying to detect child parent relationships by searching the parent for instantiations of its child components. It might be possible to instead use convenience initializers in in the child for each of it's possible parents. ie: final class BaseComponent: BootstrapComponent {}
final class A1Component: Component<EmptyDependency> {
var name: String { return "A1" }
private override init(parent: Scope) {
super.init(parent: parent)
}
convenience init(parentComponent: BaseComponent) {
self.init(parent: parentComponent)
}
}
final class A2Component: Component<EmptyDependency> {
var name: String { return "A2" }
private override init(parent: Scope) {
super.init(parent: parent)
}
convenience init(parentComponent: BaseComponent) {
self.init(parent: parentComponent)
}
}
protocol BDependency: Dependency {
var name: String { get }
}
final class BComponent: Component<BDependency> {
private override init(parent: Scope) {
super.init(parent: parent)
}
convenience init(parentComponent: A1Component) {
self.init(parent: parentComponent)
}
convenience init(parentComponent: A2Component) {
self.init(parent: parentComponent)
}
} This replaces the boilerplate declaring child components in their parents with declaring parent components in their children. But in the majority of cases it is more likely a component has more children than parents, so the boilerplate should be reduced. The generator can then create the dependency graph by identifiying the convenience initializers that match the expected pattern and using the The |
To my understanding, there are basically two steps the generator performs to ensure compile time safety.
If one tries to instantiate a component outside of it's parent say like
The following error is produced at compile time
However, because this uses pattern matching of the component name,
.init
syntax is not recognized. (This issue is also outlined here #394 )The following code does not produce the previously mentioned error because the generator doesn't recognize it as a component instantiation:
This is fine as long as the
parentScope
satisfies all ofChildComponent
's dependencies but the generator doesn't guarantee this.For example, using the following components:
The following code crashes:
With the following error that is documented as
This case should never occur with properly generated Needle code.
:I think in order to fix this issue, the generator would need to use the AST to detect component instantiations instead of just pattern matching, but I have no idea how feasible that is. If it can be done, it also shouldn't matter if components get instantiated outside of their parent at all because the AST would be used to detect them wherever they are in order to build the graph (it would be really nice if this were possible so that the boilerplate of defining child components in their parents is no longer necessary).
The text was updated successfully, but these errors were encountered: