ivlevAstef / DITranquillity

Dependency injection for iOS (Swift)
MIT License
421 stars 32 forks source link

New registration tagging proposal #125

Closed patskovn closed 6 years ago

patskovn commented 6 years ago

Proposal. Problem: Current implementation of “tags” in library based on objects types (or strings, but its not compile-safe). It is not possible now to use polymorphism like:

class A {}
class B:A {}
let tag: A.Type = B.self

c.register(MyClass.init)
    .as(MyClass.self, tag: B.self)

let myOBJ: MyClass? = c.resolve(tag)

Resolver will produce nil in myOBJ resolving, cause container will be used compile-time type of tag (A.Type), not actual type stored in tag variable.

And now we hame “name” feature that can be used similar way as tags, but string not compile-safe and it is easy to make typo mistake during development. Because both “name” and “tag” exists in library, one of them looks like a hack, that exists for solving problem of opposite implementation.

Proposal: For easier and more intuitive usage of marking registrations I suggest implement Notification.Name-like implementation or Enum implementation.

Variant1:


struct DITag {
    enum Scope<T> {
        case public
        case restricted(T.Type)
    }

    private let value: String
    private let tagScopeID: ObjectIdentifier

    Init<T>(value: String, scope: Scope<T> = .public)
}

struct MyModule {}

extension DITag { 
    static let myTag = DITag(value: “simpleTag”)
    static let myModuleTag = DITag(value: “simpleTag2”, scope: .restricted(MuModule.self))
}

container.register(MyClass.init)
   .as(MyClass.self, tag: .myTag)
   .as(MyClass.self, tag: .myModuleTag)

let obj = container.resolve(tag: .myTag)

Variant2:

protocol DITag {
    var stringValue: String { get }
}

enum MyTags: String, DITag {
   case tag1
   case tag2
}

container.register(MyClass.init)
    .as(MyClass.self, tag: MyTags.tag1)

let obj = container.resolve(tag: MyTags.tag1)

Pros:

  1. Less confusing cause we have only one tagged implementations (we have String tags and Typed tags now)
  2. More intuitive registration and resolving (enum-case like)
  3. Can be polymorphed
  4. Typo mistakes still can be avoided as in current Typed tags implementation

Difference between two variants: In variant 1 anyone from another frameworks can get access to your tagged variable without actually having access to internal tag if you declare DITag.Scope as public just by passing same string value in DITag initialisation. In variant 2, you have no possibility to share access to tag, because of capturing enum’s type in “as(_:tag:)” registration. Enum’s type capturing is mandatory cause of enum’s case string values overlapping.

ivlevAstef commented 6 years ago

it's https://github.com/ivlevAstef/DITranquillity/issues/124.

Эта реализация может узнать тэг только в момент исполнения кода. То есть не получится проверить граф на корректность.

patskovn commented 6 years ago

Разве сейчас по имени нет возможности проверить граф на корректность?

ivlevAstef commented 6 years ago

Есть. но у имени кастрированный функционал - его например нельзя задать в методе инициализации. Кокраз таки из-за того что надо было сохранять валидацию.