> 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

Reply via email to