> On Nov 15, 2016, at 05:24 , Jeremy Pereira <jeremy.j.pere...@googlemail.com> > wrote: > > >> On 15 Nov 2016, at 10:33, Rick Mann <rm...@latencyzero.com> wrote: >> >> Well, that's not really any different than a switch statement, in that it >> has to be maintained. > > Yes, but I would argue that it is a good thing because you need to do some > validation before you instantiate the class anyway. > > Furthermore, it gives you more flexibility in terms of initialisation because > the closure can invoke any initialiser regardless of parameters and can do > other processing as well.
Yeah, but that's not the flexibility I need. And with good reflection/introspection, I can do all the validation I need dynamically. In an ideal world, I could do something like this: let pathRenderers = classesThatImplement(protocol: Renderer) for pr in pathRenderers { for ini in pr.initializers { if ini.has(signature: (Path)) { let renderer = pr.instantiate(aPath) return } } } Obviously more complicated than this, but you get the idea. > >> >>> On Nov 15, 2016, at 01:50 , Jeremy Pereira >>> <jeremy.j.pere...@googlemail.com> wrote: >>> >>> Perhaps I’m missing something here, but why not use a map? >>> >>> let factoryMap = [ String : () -> SuperClassOrCommonProtocol ] = [ >>> “MySubClass" : { return MySubClass() }, … ] >>> >>> … >>> >>> guard let factoryMethod = factoryMap[theClassName] else { /* error */ } >>> return factoryMethod() >>> >>> This is an approach I always ended up taking in Objective-C anyway, >>> because, if you don’t know what’s in the string, you need to validate it >>> (imagine if the user of your app finds out that they can cause you to >>> instantiate any arbitrary class) and if you do know what’s in the string, >>> why are you not creating the instance directly? >>> >>> >>>> On 14 Nov 2016, at 23:48, Rick Mann via swift-users >>>> <swift-users@swift.org> wrote: >>>> >>>> Thanks, David. That's interesting as a thought exercise, but doesn't >>>> really get me away from having switch statements. I'll probably end up >>>> just "slightly polluting" my classes by adding extension methods to create >>>> the appropriate auxiliary classes. Sure wish Swift supported optional >>>> methods without @objc (I guess it's not that big a deal to use @objc). >>>> >>>>> On Nov 13, 2016, at 11:19 , David Sweeris <daveswee...@mac.com> wrote: >>>>> >>>>> >>>>>> On Nov 13, 2016, at 1:55 AM, Rick Mann <rm...@latencyzero.com> wrote: >>>>>> >>>>>> >>>>>>> On Nov 12, 2016, at 22:47 , David Sweeris <daveswee...@mac.com> wrote: >>>>>>> >>>>>>> >>>>>>>> On Nov 13, 2016, at 00:38, Rick Mann via swift-users >>>>>>>> <swift-users@swift.org> wrote: >>>>>>>> >>>>>>>> So, it seems there's still no way to do something like instantiate a >>>>>>>> class given only its name (as a String)? >>>>>>>> >>>>>>>> In my situation, I have a number of subclasses (or protocol >>>>>>>> implementations), which parallel some other class hierarchy. I need to >>>>>>>> dynamically create one based on the name of another. I don't want the >>>>>>>> latter classes to "know" anything about the former. >>>>>>> >>>>>>> Not that I know of... If this is all your code, can you fake it by >>>>>>> switching over the type's name? >>>>>> >>>>>> Yeah, it just happens in a few places, would be nice to write the code >>>>>> once and then just ensure classes exist. I know I could do it >>>>>> subclassing NSObject, but Swift really ought to have proper reflection. >>>>> >>>>> Reflection is on the todo list (although I can’t recall if it’s in-scope >>>>> for Swift 4). >>>>> >>>>> There’s also the possibility of putting the names of the classes you want >>>>> to instantiate into an enum. In fact, if all the classes in question have >>>>> a common superclass, you could this: >>>>> class MyAwesomeSuperClass { required init() {} } >>>>> class MyAwesomeSubClass : MyAwesomeSuperClass {} >>>>> class Whatever : MyAwesomeSuperClass {} >>>>> class Etc : Whatever {} >>>>> enum ClassNames : String { >>>>> //Unfortunately the value of each case has to be a literal, so >>>>> //you can’t just say `case etc = "\(Etc.self)"` >>>>> case myAwesomeSuperClass = "MyAwesomeSuperClass" >>>>> case myAwesomeSubClass = "MyAwesomeSubClass" >>>>> case whatever = "Whatever" >>>>> case etc = "Etc" >>>>> init(_ instance: MyAwesomeSuperClass) { self = ClassNames.init(rawValue: >>>>> "\(type(of: instance))")! } >>>>> init(_ type: MyAwesomeSuperClass.Type) { self = ClassNames.init(rawValue: >>>>> "\(type)")! } >>>>> var type: MyAwesomeSuperClass.Type { >>>>> switch self { >>>>> case .myAwesomeSuperClass: return MyAwesomeSuperClass.self >>>>> case .myAwesomeSubClass: return MyAwesomeSubClass.self >>>>> case .whatever: return Whatever.self >>>>> case .etc: return Etc.self >>>>> } >>>>> } >>>>> } >>>>> var etc = Etc() >>>>> var className = ClassNames(etc) >>>>> var newEtc = className.type.init() >>>>> >>>>> The same trick works if all the types in question conform to the same >>>>> protocol, too: >>>>> protocol MyAwesomeProtocol { >>>>> init() >>>>> func toIntMax() -> IntMax >>>>> } >>>>> extension Int : MyAwesomeProtocol {} >>>>> struct Five : MyAwesomeProtocol { func toIntMax() -> IntMax { return 5 } } >>>>> enum ProtocolNames : String { >>>>> case five = "Five" >>>>> case int = "Int" >>>>> init(_ instance: MyAwesomeProtocol) { self = ProtocolNames.init(rawValue: >>>>> "\(type(of: instance))”)! } >>>>> init(_ type: MyAwesomeProtocol.Type) { self = >>>>> ProtocolNames.init(rawValue: "\(type)")! } >>>>> var type: MyAwesomeProtocol.Type { >>>>> switch self { >>>>> case .five: return Five.self >>>>> case .int: return Int.self >>>>> } >>>>> } >>>>> } >>>>> var five = Five() >>>>> var fiveName = ProtocolNames(five) >>>>> var newFive = fiveName.type.init() >>>>> >>>>> Either way, though, you’ll have to do something like if let nf = newFive >>>>> as? Int {…} if you want to use any functionality that isn’t explicitly in >>>>> the superclass or protocol. >>>>> >>>>> It certainly involves some boilerplate code, but it also has the >>>>> advantages of validating the name before you try to use it and ensuring >>>>> that any switch statements can actually handle all the classes. >>>>> >>>>> - Dave Sweeris >>>> >>>> >>>> -- >>>> Rick Mann >>>> rm...@latencyzero.com >>>> >>>> >>>> _______________________________________________ >>>> swift-users mailing list >>>> swift-users@swift.org >>>> https://lists.swift.org/mailman/listinfo/swift-users >>> >> >> >> -- >> Rick Mann >> rm...@latencyzero.com >> >> > -- Rick Mann rm...@latencyzero.com _______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users