Search code examples
swiftinheritanceoverridinggetter-setter

Overriding getter in Swift


I have a situation where I need to override the getter of a property.

Let's say we have:

public class MyBaseClass {
    private var _name: String
    public internal(set) var name: String {
        get {
            return self._name
        }
        set {
            self._name = newValue
        }
    }
}

Nothing really fancy, I guess.

Now, if I try to override the getter in a derived class:

public class MyDerivedClass: MyBaseClass {
    public var name: String {
        get {
            return "Derived - \(super.name)"
        }
    }
}

I get the compile error: Cannot override mutable property with read-only property 'name'.

If I try to add the setter and overriding it:

public class MyDerivedClass: MyBaseClass {
    public internal(set) var name: String {
        get {
            return "Derived - \(super.name)"
        }
        set {
            super.name = newValue
        }
    }
}

I get the error: Setter of overriding var must be as accessible as the declaration it overrides.

And if I try the following:

public class MyDerivedClass: MyBaseClass {
    public internal(set) var name: String {
        get {
            return "Derived - \(super.name)"
        }
    }
}

Then, the compiler crashes...

How can I achieve to override only the getter ?


Solution

  • This works for me:

    public class MyBaseClass {
        private var _name: String = "Hi"
        public internal(set) var name: String {
            get {
                return self._name
            }
            set {
                self._name = newValue
            }
        }
    }
    
    public class MyDerivedClass:MyBaseClass {
        override public var name: String {
            get {
                return "Derived - \(super.name)"
            }
            set {
                super._name = newValue
            }
        }
    }
    
    MyDerivedClass().name
    

    EDIT

    This code works for me in a playground, placing it in the Sources -> SupportCode.swift file

    public class MyBaseClass {
    private var _name: String = "Hi"
    public internal(set) var name: String {
        get {
            return self._name
        }
        set {
            self._name = newValue
        }
    }
    public init() {
    
    }
    
    }
    
    public class MyDerivedClass:MyBaseClass {
        override public var name: String {
            get {
                return "Derived - \(super.name)"
            }
            set {
               // do nothing
            }
        }
       public override init() {
    
        }
    }
    

    It's a bit of a bodge because I get the same warning as you that internal(set) cannot be placed before the overridden subclass variable. It may well be a bug. And also I'm cheating to make sure the setter of the derived class does nothing.

    A more common use of internal(set) or private(set) is to have code like this, which is similar to that in the documentation:

    public class MyBaseClass {
        public private(set) var _name: String = "Hi"
        public var name: String {
            get {
                return self._name
            }
            set {
                self._name = newValue
            }
        }
        public init() {
    
        }
    
    }
    
    public class MyDerivedClass:MyBaseClass {
        override public var name: String {
            get {
                return "Derived - \(super.name)"
            }
            set {
               super._name = newValue
            }
        }
       public override init() {
    
        }
    }
    

    Here the setter can be read directly with MyDerivedClass()._name but it cannot be altered, e.g. this MyDerivedClass()._name = "Fred" would raise an error but MyDerivedClass().name = "Fred" would be OK.