2

I want to create a class, so that the it's subclasses after calling a function a, will receive a new object of the type Self. I'm insuring, that the subclasses will have the init() method.

In a way I want to clone the object, but actually it's more than that, since I want to create a clone with modified values of the original, so I don't really want to use swifty copy constructor syntax

Why it doesn't work? Definitely this:

func myCustomCopy(modificationCommand: Command) -> Test {
    let newInt = modificationCommand.execute(self.myInt)
    return Test(newInt: newInt)
}

is not what I want.

Example:

protocol Testable {
    var myInt: Int { get set }
    init(newInt: Int)
}

class Test: Testable {
    var myInt = 10
    required init(newInt: Int) { myInt = newInt }

    func myCustomCopy(modificationCommand: Command) -> Self {
        let newInt = modificationCommand.execute(self.myInt)
        return self.init(newInt: newInt)
    }
}
denis631
  • 1,765
  • 3
  • 17
  • 38
  • 1
    1) Why isn't that what you want? – Alexander Mar 12 '17 at 17:20
  • 2) Why do you need a function `a()` in the first place? – Alexander Mar 12 '17 at 17:20
  • 3) The last code snippet is totally fine if you just remove the `a()` function entirely. Every subclass will require to have that initializer, and it'll always return the same type of the subclass – Alexander Mar 12 '17 at 17:21
  • Because I get a base class instantiation and I want to get the Subclass Object returned. In a way it's a copy constructor, but it's more than that. I know that copy constructors are done in another fashion in Swift – denis631 Mar 12 '17 at 17:21
  • That's not true. 1) a required initializer returns the same type as the class it's called on, whether it's a base class or a subclass. 2) It has absolutely nothing to do with copy construction. 0. – Alexander Mar 12 '17 at 17:24
  • You just completely changed the entire meaning of your question. – Alexander Mar 12 '17 at 17:25
  • http://stackoverflow.com/q/25808972/3141234 – Alexander Mar 12 '17 at 17:26
  • 3
    Note that you may use the (dynamically typed) metatype returned by `type(of:)` to access an initializer of the concrete type of the metatype. In your case, you could use the metatype of `self` to call an initializer of the concrete type of `self`, e.g. `func myCustomCopy() -> Self { return type(of: self).init() }`. – dfrib Mar 12 '17 at 17:28
  • @Alexander it's still the same. I want to return Self from my function. And the question is how – denis631 Mar 12 '17 at 17:29
  • @dfri thank you! It worked. Do you want to write a response, so I can mark the question as closed ? – denis631 Mar 12 '17 at 17:33
  • Happy to help. Sure, I added a somewhat extended version of my comment as an answer. – dfrib Mar 12 '17 at 17:37

1 Answers1

2

You may use the (dynamically typed) metatype returned by type(of:) to access an initializer of the concrete type of the metatype. Quoting the Language Reference - Metatypes

Use an initializer expression to construct an instance of a type from that type’s metatype value. For class instances, the initializer that’s called must be marked with the required keyword or the entire class marked with the final keyword.

So in your case, you could use the metatype of self to call a required initializer of the concrete type of self, e.g.

func myCustomCopy() -> Self {
    return type(of: self).init()
}

Note that, as specified in the quote above, since you are working with a non-final class, the initializer must be a required one.

dfrib
  • 70,367
  • 12
  • 127
  • 192