Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Restructure
@Dependency
property and use BFS for DependencyManager (#…
…112) # Restructure `@Dependency` property and use BFS for DependencyManager ## ♻️ Current situation & Problem The `Module` and dependency system is very powerful and useful infrastructure of the Spezi framework ecosystem allowing it to be modularized. There was immense thought put into it to generalize the concept of dependency declaration between modules. With recent PRs it has become even more powerful support a lot of different use cases like dynamism (e.g., like modeling Bluetooth devices as modules). However, it some scenarios the `@Dependency` property lacks the expressiveness as required in certain use cases. For example, it is currently always required to either specify a default value (either manually or through `DefaultInitializable`) or declare it as an optional dependency. Simply, declaring a required dependency that is assumed to be present, cannot be modeled. For example, a module A, might configure a module B and C, where B has a required dependency to C (as it knows it is always configured by A and therefore can safely assume that C is present). This is currently not possible with either a) having to unwrap a optional dependency all the time or b) declaring a dependency with a default value which might be not always be possible if there are initializer arguments required. Secondly, you currently cannot have a guarantee that a given module **instance** you provide to the `@Dependency` property wrapper is actually loaded as it is always used as a default argument and a module declared on the outside takes precedence. The changes of this PR are listed in the next section. ## ⚙️ Release Notes This PR introduces several changes to the dependency system. * You can specify **required** modules without providing a default value like below: * `@Depenency(Example.self) var example` * You can manually request loading a module in any case by calling the special initializer `_example = Dependency(load: myInstance)` or using any array based initializers. * The PR makes certain initializers to require to specify the Module type as we are reaching a point where Swift has troubles resolving the different non-argument initializers: * Instead of specifying `@Dependency var example: Example?` you have to specify `@Dependency(Example.self) var example: Example?. * Instead of specifying `@Dependency var example: Example` (for `DefaultInitializable`), you will specify `@Dependency(Example.self) var example` for a required dependency. The default value will automatically be created. * Lastly, this PR changes the DependencyManager from using a depth-first search to a breath-first search to avoid unexpected initialization of default values. Old initializers are marked deprecated and shall be removed in the next major version release. ## 📚 Documentation This PR updates documentation to refer to the most recent versions of the `@Dependency` property wrapper. ## ✅ Testing New unit tests were added to cover new cases. We added some verification that deprecated initializers still work as expected. ## 📝 Code of Conduct & Contributing Guidelines By submitting creating this pull request, you agree to follow our [Code of Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md) and [Contributing Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md): - [x] I agree to follow the [Code of Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md) and [Contributing Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md).
- Loading branch information