`diff Swift C++`: generics vs templates

If you are familiar with C++ template programming you will know that it's bloody (pun not intended) awesome but has perhaps the steepest learning curve of any useful feature of a mainstream language. If you just use it through standard library with the likes of containers and smart pointers, you don't have to learn about it much if anything. If you want to write your own template functions and classes, you can do that pretty easily. But if you want to unleash the firepower of that fully operational battle station... then you have to work a lot at it and go through and understand lot of previous art like Modern C++ Programming book and modern template-based libraries like many in Boost.

I managed to achieve a reasonable mastery of templates and for some things it was worth it. As an example I could create a compile-time list of enums that would create, again during compile-time, a single class that would intercept all SQL Server operations matching the said enums and provide hooks for custom handling. Then take the same template in another program, provide a different compile-time list and you have a different class, all with new enums baked in so no dynamic code.

But that was when I was single and without kids. Now I need more pragmatic stuff even if sometimes it feels stiffening.

Generics in Swift are almost the same as generics in C#. The types in them are either treated with the standard set of operations available for all types (look at the Stack example in Swift book) or they are protocol-based (interface for the rest of the world, usually implemented as struct in C++) with type constraints defining what operations can be execute. They don't get resolved during compile time like C++ templates but rather they get compiled on their own and are then execute directly as that during runtime. That said, compiler may choose to specialize a generic type or function depending on active optimizations.

Similarities

In Swift:

  1. You can create generic functions and based on classes, structs and enums you can create generic types
  2. You can overload on generics providing specialized functions for specific data types. For example, this will recognized the "more specialized" function and execute it:

    func testMethod<T: Comparable>(v: T) -> T {
        return v
    }
    func testMethod(v: Int) -> Int {
        return v * 12345
    }
    println(testMethod(1)) // Outputs 12356
    println(testMethod(1.0)) // Outputs 1.0
    
  3. You can specialize method functions within a generic type thus again providing a specialized function for specialized cases. For example:

    class TestClass<T> {
        func testMethod<U: Equatable>(v: U) -> Bool {
            return v == v
        }
        func testMethod(v: T) -> T {
            return v
        }
    }
    var v = TestClass<Int>()
    v.testMethod(1.0) // Prints out true
    v.testMethod(1) // Prints out 1
    

(My apologies for lousy formatting but Markdown in Ghost is messing with me right now)

  1. You can inherit argument types or generic classes receiving argument type so Anarchy Curiously Recurring Template Pattern is not dead!

But it can't (yet?) quite work as in C++ or C# as Swift gives an error of classes derived from generic classes must also be generic. So if you really need it you can use an empty tag type and then use it for instantiation:

//  Base class - put your reusable code here
class Base<Derived> {}
//    Derived class indirection - put your specific code here
class DerivedIndirection<T> : Base<DerivedIndirection> {}
//    Empty tag struct so that indirection can be unique
struct DerivedTag {}
//    Type alias for the DerivedIndirection with DerivedTag
typealias Derived = DerivedIndirection<DerivedTag>
//    Later...
//    Another empty tag structure
struct AnotherDerivedTag {}
//    A completely different derived type
typealias AnotherDerived = DerivedIndirection<AnotherDerivedTag>

I have often used for code reuse through the base class and correctly typed parameters and return classes (as Wikipedia puts it)

Differences

In Swift:

  1. You can't create generic protocols (or at least I couldn't manage to do it) and even C# allows that.
  2. You don't have partial specialization (of anything) so you can't do a lot of beautiful metaprogramming. Again, not sure if that was worth it from a practical point of view, but it was certainly lovely at the times (and maddening at the others). This is same as in C#.
  3. You can't specify integers or other compile-time constants as generic arguments (same as in C#)
  4. You can't smply specify any type as generic parameter and hope it fulfills the requirements during compile time. Since generics are compiled on their own and not instantiated during compile time you must use type constraints to allow custom operations (e.g. use Equatable if you want to compare values of a generic type). This is same as in C# and it offers many advantages (smaller code size, ability to export generics from modules without access to source code, separate compilation of generics and types that will be instantiating them and so on).

I'm sure there are many other similarities and differences regarding generics and I'll be tackling those as I come upon them.

Author

Ivan Erceg

Software shipper, successful technical co-founder, $1M Salesforce Hackathon 2014 winner