GithubHelp home page GithubHelp logo

Comments (2)

rudro avatar rudro commented on August 15, 2024

Yes, as you noticed .init breaks needle's understand of the graph and that causes runtime issues. As you noted, it's really hard to know the type of the class being constructed because the AST has no form of type-inference. In a simple one line function, maybe the return type can tell us the type but in the case you give above, we have to walk back to the let secondComponent: SecondComponent property and that would be quite hard and difficult to generalize for all cases.

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.

from needle.

dbagwell avatar dbagwell commented on August 15, 2024

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 .init and remove the required child component bolierplate code.

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 parentComponent type names to link the component with its parents.

The private override init(parent: Scope) is there to prevent potential runtime errors that might happen if someone were to try using the component's designated initializer with a parent that the graph doesn't know about. the generator could enforce that the component override this init as private (as well as ensure that super.init isn't called anywhere else in the component) or produce an error at compile time. This would resolve the issue with .init because the generator no longer needs to try to detect component instantiations because the only available initializers are ones that require the components exact parent types as defined in the dependency graph.

from needle.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.