Abstract functions in Swift Language

56,739

Solution 1

There no concept of abstract in Swift (like Objective-C) but you can do this :

class BaseClass {
    func abstractFunction() {
        preconditionFailure("This method must be overridden") 
    } 
}

class SubClass : BaseClass {
     override func abstractFunction() {
         // Override
     } 
}

Solution 2

What you want is not a base class, but a protocol.

protocol MyProtocol {
    func abstractFunction()
}

class MyClass : MyProtocol {
    func abstractFunction() {
    }
}

If you don't supply abstractFunction in your class it's an error.

If you still need the baseclass for other behaviour, you can do this:

class MyClass : BaseClass, MyProtocol {
    func abstractFunction() {
    }
}

Solution 3

I port a fair amount of code from a platform that supports abstract base classes to Swift and run in to this a lot. If what you truly want is the functionality of an abstract base class, then that means that this class serves both as an implementation of shared based class functionality (otherwise it would just be an interface/protocol) AND it defines methods that must be implemented by derived classes.

To do that in Swift, you will need a protocol and a base class.

protocol Thing
{
    func sharedFunction()
    func abstractFunction()
}

class BaseThing
{
    func sharedFunction()
    {
        println("All classes share this implementation")
    }
}

Note that the base class implements the shared method(s), but does not implement the protocol (since it doesn't implement all of the methods).

Then in the derived class:

class DerivedThing : BaseThing, Thing 
{
    func abstractFunction() 
    {
        println("Derived classes implement this");
    }
}

The derived class inherits sharedFunction from the base class, helping it satisfy that part of the protocol, and the protocol still requires the derived class to implement abstractFunction.

The only real downside to this method is that since the base class does not implement the protocol, if you have a base class method that needs access to a protocol property/method you will have to override that in the derived class, and from there call the base class (via super) passing self so that the base class has an instance of the protocol with which to do its work.

For example, lets say that sharedFunction needed to call abstractFunction. The protocol would stay the same, and the classes would now look like:

class BaseThing
{
    func sharedFunction(thing: Thing)
    {
        println("All classes share this implementation")
        thing.abstractFunction()
    }
}

class DerivedThing : BaseThing, Thing 
{
    func sharedFunction()
    {
        super.sharedFunction(self)
    }

    func abstractFunction() 
    {
        println("Derived classes implement this");
    }
}

Now the sharedFunction from the derived class is satisfying that part of the protocol, but the derived class is still able to share the base class logic in a reasonably straightforward way.

Solution 4

This one seems to be the "official" way how Apple is handling abstract methods in UIKit. Take a look at UITableViewController and the way it's working with UITableViewDelegate. One of the very first things you do, is to add a line: delegate = self. Well, that's exactly the trick.

1. Put the abstract method in a protocol
protocol AbstractMethodsForClassX {
    func abstractMethod() -> String
}
2. Write your base class
/// It takes an implementation of the protocol as property (same like the delegate in UITableViewController does)
/// And does not implement the protocol as it does not implement the abstract methods. It has the abstract methods available in the `delegate`
class BaseClassX {
    var delegate: AbstractMethodsForClassX!

    func doSomethingWithAbstractMethod() -> String {
        return delegate.abstractMethod() + " - And I believe it"
    }
}
3. Write the Subclass(es).
/// First and only additional thing you have to do, you must set the "delegate" property
class ClassX: BaseClassX, AbstractMethodsForClassX {
    override init() {
        super.init()
        delegate = self
    }

    func abstractMethod() -> String {return "Yes, this works!"}
}
Here is, how to you use all that
let x = ClassX()
x.doSomethingWithAbstractMethod()

Check with Playground to see the output.

Some Remarks

  • First, a lot of answers were given already. I hope somebody finds all the way down to this one.
  • The question actually was, to find a pattern that implements:
    • A class calls a method, that has to be implemented in one of its derived subclasses (overridden)
    • In best case, if the method is not overridden in the subclass, get an error during compile time
  • The thing about abstract methods is, that they're a mixture of an interface definition and part of an actual implementation in the base class. Both at the same time. As swift is very new and very clean defined, it has no such convienience but "unclean" concepts (yet).
  • To me (a poor old Java guy), this problem evolves from time to time. I've read thru all the answers in this post and this time I think I found a pattern, that looks feasable - at least to me.
  • Update: It looks like the UIKit implementers at Apple use the same pattern. UITableViewController implements UITableViewDelegate but still needs to be registers as delegate by explicitely setting the delegate property.
  • This all is tested on Playground of Xcode 7.3.1

Solution 5

Well, I know that I am late to the game and that I might be taking advantage of the changes that have happened. Sorry about that.

In any case, I would like to contribute my answer, because I love doing testing and the solutions with fatalError() is, AFAIK, not testable and the ones with exceptions are much harder to test.

I would suggest to use a more swifty approach. Your goal is to define an abstraction that has some common details, but that is not fully defined, i.e. the abstract method(s). Use a protocol that defines all the expected methods in the abstraction, both the ones that are defined, and also the ones that aren't. Then create a protocol extension that implements the methods that are defined in your case. Finally, any derived class must implement the protocol, which means all the methods, but the ones that are part of the protocol extension already have their implementation.

Extending your example with one concrete function:

protocol BaseAbstraction {
    func abstractFunction() {
        // How do I force this function to be overridden?
    }
}

extension BaseAbstraction {
    func definedFunction() {
        print("Hello")
}

class SubClass : BaseAbstraction {
    func abstractFunction() {
        // No need to "Override". Just implement.
    }
}

Notice that by doing this, the compiler is again your friend. If the method is not "overridden", you will get an error at compile time, instead of the ones that you would get with fatalError() or exceptions that would happen at run time.

Share:
56,739
kev
Author by

kev

Updated on August 20, 2020

Comments

  • kev
    kev almost 4 years

    I'd like to create an abstract function in swift language. Is it possible?

    class BaseClass {
        func abstractFunction() {
            // How do I force this function to be overridden?
        }
    }
    
    class SubClass : BaseClass {
        override func abstractFunction() {
            // Override
        }
    }
    
    • David Berry
      David Berry about 10 years
      This is pretty close to your other question but the answer here seems a little better.
    • kev
      kev about 10 years
      The questions are similar but the solutions are far different because a abstract class has different use cases than an abstract function.
    • David Berry
      David Berry about 10 years
      Yep, why I didn't vote to close either, but the answers there won't be useful beyond "you can't" Here you got the best available answer :)
  • Erik
    Erik about 10 years
    Alternatively you can use assert(false, "This method must be overriden by the subclass").
  • nathan
    nathan about 10 years
    or fatalError("This method must be overridden")
  • André Fratelli
    André Fratelli almost 10 years
    assertions will require a return statement when a method has a return type. I think fatalError() is better for this one reason
  • JeremyP
    JeremyP almost 10 years
    Assertions also seem not to be compiled in for release builds.
  • JeremyP
    JeremyP almost 10 years
    Apparently, neither is fatalError()
  • Jageen
    Jageen over 9 years
    @jaumard If you write something like (No concept of abstract in swift) reference link from apple is appreciated.
  • Dan Rosenstark
    Dan Rosenstark over 9 years
    Great understanding and good depth on the "the base class does not implement the protocol"... which is kind of the point of an abstract class. I'm baffled that this basic OO feature is missing, but then again, I was raised on Java.
  • bandejapaisa
    bandejapaisa over 9 years
    This doesn't quite work. If BaseClass wants to call those empty functions, then it would also have to implement the protocol, and then implement the functions. Also the subclass still isn't forced to implement the functions at compile time, and you not compelled to implement the protocol either.
  • Steve Waddicor
    Steve Waddicor over 9 years
    Baseclass has nothing to do with the protocol. I said "for other behaviour". The protocol is introduced for MyClass. As to not being forced to implement at compile time, you clearly haven't actually tried it.
  • bandejapaisa
    bandejapaisa over 9 years
    That's my point.... BaseClass has nothing to do with the protocol, and to act like an abstract class it should have something to do with it. To clarify what I wrote "If BaseClass wants to call those empty functions, then it would also have to implement the protocol which would force you to implement the functions - which then leads to the Subclass not being forced to implement the functions at compile time, because the BaseClass has already done it".
  • Steve Waddicor
    Steve Waddicor over 9 years
    Baseclass has nothing to do with the protocol. Making it so would be changing the code I presented. There is nothing wrong with the code given.
  • Steve Waddicor
    Steve Waddicor over 9 years
    To be clear, an abstract function has two features: It no functionality, and it must be overridden. In Swift this is provided by a protocols. There is no other way. Certain other languages allow a base thingy to provide both abstract functions and ordinary virtual functions. Baseclass appears in my example to indicate this is possible with swift but requires both a protocol AND a base class to achieve. "It doesn't quite work" is nonsense. It works perfectly. If you want to say that Swift doesn't provide abstract funcs in the same way as some other particular language, well that's different.
  • Steve Waddicor
    Steve Waddicor over 9 years
    It is an abstract function in the Swift language. Period. It works perfectly. That it isn't the same as some other unnamed language you're used to is irrelevant.
  • Joshcodes
    Joshcodes over 9 years
    Do you mean AbstractMethodException().raise() ?
  • André Fratelli
    André Fratelli over 9 years
    Err... Probably. I can't test right now, but if it works that way, than yes
  • Kametrixom
    Kametrixom about 9 years
    Also there is preconditionFailure("Bla bla bla") in Swift which will execute in release builds and also eliminates the need of a return statement. EDIT: Just found out that this method basically is equal to fatalError() but it's the more proper way (Better documentation, introduced in Swift along with precondition(), assert() and assertionFailure(), read here)
  • LoveMeow
    LoveMeow about 9 years
    what if the function has a return type?
  • ProgrammierTier
    ProgrammierTier almost 9 years
    What I like about this approach is that I don't have to remember to implement a protocol in the inheriting class. I have a base class for my ViewControllers, and this is how I enforce ViewController specific, optional functionality (e.g. app became active, etc.) that might get invoked by base class functionality.
  • Puppy
    Puppy almost 9 years
    That really depends on how you define "abstract". The whole point of an abstract function is that you can put it on a class that can do normal class things. For example, the reason I want this is because I need to define a static member which you can't seem to do with protocols. So it's hard for me to see that this meets the useful point of an abstract function.
  • Glenn Howes
    Glenn Howes over 8 years
    I think you can use a combination of Protocols and the new Protocol Extensions to get a better solution than abstract base classes.
  • David James
    David James over 8 years
    I think the concern with the upvoted comments above is that this does not conform to the Liskov Substitution principle which states "objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program." It's assumed this is an abstract type. This is particularly important in the case of Factory Method pattern where the base class is responsible for creating and storing properties that originate from the sub class.
  • Fabrizio Bartolomucci
    Fabrizio Bartolomucci over 8 years
    Yet the implementation does not allow to seamlessly implement the Template Function method where the template method calls a wide number of abstract methods implemented in the subclasses. In this case you should write them both as normal methods in the super class, as methods in the protocol and again as implementations in the subclass. In practice you have to write three times the same stuff and only rely on the override check to be sure of not making any disastrous misspelling! I really hope now that Swift is open to developers, full-fledged abstract function shall be introduces.
  • Fabrizio Bartolomucci
    Fabrizio Bartolomucci over 8 years
    The benefit of abstract methods is that the checks are done at compile time.
  • Shoerob
    Shoerob over 7 years
    An abstract base class and a protocol are not the same thing.
  • Shoerob
    Shoerob over 7 years
    So much time, and code could be saved by introducing the "protected" keyword.
  • Radian Jheng
    Radian Jheng about 7 years
    If the instance of the SubClass is upCasted to BaseClass, it will call the methods of BaseClass. This is not a good way to do implement abstract methods.
  • Christophe
    Christophe about 7 years
    This main feature of an abstract class is that there is a compile time check to prevent it from getting instantiated, and the same for the derived (abstract) classes which haven't overridden the pure virtual function. While this solution is a nice work around, it transfers this check to runtime. This is nicely explained by Apple here: github.com/apple/swift-evolution/blob/master/proposals/…
  • Zaporozhchenko Oleksandr
    Zaporozhchenko Oleksandr over 6 years
    don't use assert, because on archiving, u will get 'Missing return in a function expected to return' error. Use fatalError("This method must be overriden by the subclass")
  • Tomasz Nazarenko
    Tomasz Nazarenko over 6 years
    Maybe not perfect, because I have problems hiding the interface of the class from other classes, but this is enough what I needed to implement classic Factory Method in Swift.
  • Jake T.
    Jake T. over 6 years
    Hmmm. I like the looks of this answer a lot more, but I'm also not sure it's suitable. I.e., I have a ViewController that can be displaying information for a handful of different types of objects, but the purpose of displaying that information is all the same, with all the same methods, but pulling and putting together the information differently based on the object. So, I have a parent delegate class for this VC, and a subclass of that delegate for each type of object. I instantiate a delegate based on the object passed in. In one example, each object has some relevant comments stored.
  • Jake T.
    Jake T. over 6 years
    So I have a getComments method on the parent delegate. There's a handful of comment types, and I want the ones relevant to each object. So, I want the subclasses to not compile when I do delegate.getComments() if I don't override that method. The VC just knows it has a ParentDelegate object called delegate, or BaseClassX in your example, but BaseClassX does not have the abstracted method. I'd need the VC to specifically know that it is using the SubclassedDelegate.
  • jboi
    jboi over 6 years
    I hope I understand you right. If not, do you mind to ask a new question where you can add some code? I think you just need to have an if-statement in ‚doSomethingWithAbstractMethod‘ checking, if delegate is set or not.
  • Apfelsaft
    Apfelsaft almost 6 years
    Imo the best answer.
  • joehinkle11
    joehinkle11 over 4 years
    Good answer, but your base abstraction isn't capable on storing properties, however
  • Enricoza
    Enricoza over 4 years
    Also if you want to call an "abstract" method in another method inside your base class you will end up calling your base method even if it is actually overridden.
  • Enricoza
    Enricoza over 4 years
    It' worth mentioning that assigning self to the delegate creates a retain cycle. Maybe it's better to declare it as weak (which is commonly a good idea for delegates)