theapache64
theapache64

Reputation: 11754

Abstract classes in Swift

I've been working in Java for past few years, and now am learning Swift. I was trying to implement Java abstract classes in Swift and found out that Swift doesn't support it. I've also seen that the abstract classes can be achieved through protocol, but as my class contains generic type, I am bit confused about it.

I've created a Java class structure and tried to convert it to Swift, But I failed. Here's the class

import java.util.List;
import java.util.ArrayList;

public class HelloWorld{

     public static void main(String []args){
        D d = new D();
        d.sayHello();
        d.sayHi();
        d.sayGracias();

        System.out.println(d.get("Hello"));
     }

     static class A{
         public void sayHello(){
             System.out.println("Hello from A");
         }
     }

     static class B<R> extends A{
        public void sayHi(){
            System.out.println("Hi from B");
        }   
     }

     static abstract class C<M,R> extends B<R>{

         public abstract List<M> get(R r);

         public void sayGracias(){
            System.out.println("Gracias from C");
         } 
     }

     static class D extends C<String, String>{

         @Override 
         public List<String> get(String s){
             List<String> list = new ArrayList<String>();
             list.add(s);
             return list;
         }
     }

}

Output

Hello from A
Hi from B
Gracias from C
[Hello]

Asking all my doubts and questions about this topic would be a mess. So the converted code (Java -> Swift) will fix all my doubts. Could anyone help me by converting the above code to Swift?

NOTE: I need forced overriding like in Java.

Upvotes: 3

Views: 529

Answers (1)

Sweeper
Sweeper

Reputation: 273115

I strongly suggest you redesign your model in Swift. Just like when translating spoken languages, the outcome can sound very awkward, programming languages, when translated, can look awkward too. If you still want to translate from Java, read on.


The really hard problem to solve here is that B is generic. If B wasn't generic, everything would work way better in Swift.

For now, you just have to use a class and pretend it is a protocol:

class A {
    func sayHello() {
        print("Hello from A")
    }
}

class B<R> : A {
    func sayHi() {
        print("Hi from B")
    }
}

class C<M, R> : B<R> {
    // this fatalError() thing is really ugly, but I can't think of any other workarounds
    func get(r: R) -> [M] { fatalError() }
    func sayGracias() {
        print("Gracias from C")
    }
}

class D : C<String, String> {
    override func get(r: String) -> [String] {
        return [r]
    }
}

let d = D()
d.sayHello()
d.sayHi()
d.sayGracias()
print(d.get(r: "Hello"))

If B were not generic (you are not using the generic argument anyway), then this can be done:

class A {
    func sayHello() {
        print("Hello from A")
    }
}

class B : A {
    func sayHi() {
        print("Hi from B")
    }
}

protocol C {
    // associated types in Swift are kind of like generic parameters for protocols
    associatedtype M
    associatedtype R
    func get(r: R) -> [M]
}

extension C {
    func sayGracias() {
        print("Gracias from C")
    }
}

// You have to specify that D inherits from B as well since protocols can't inherit from classes
class D : B, C {
    typealias M = String
    typealias R = String

    func get(r: String) -> [String] {
        return [r]
    }
}

let d = D()
d.sayHello()
d.sayHi()
d.sayGracias()
print(d.get(r: "Hello"))

Upvotes: 1

Related Questions