Initialization in Modern C++ vs Apple’s Swift

Time for another great guest blog post from Bradley Needham to follow up on his very popular Swift vs. C++ post. Enjoy!


Initialization in Modern C++ vs Apple’s Swift

A little while ago I wrote a short post comparing some of the basic features of Modern C++ and Apple’s Swift. It was far from comprehensive, basically only touching on the constructs mentioned in Michael Kennedy’s post Comparison of Python and Apple’s Swift Programming Language Syntax. However the post did generate enough interest that I decided to continue the comparison by looking at one of the differences I find interesting between the two languages, initialization. Initialization is very important in any language and both C++ and Swift have built in constructs and checks to help make sure that objects get completely initialized before they are used.

Initialization syntax

Let us start with the syntax of the two languages.

Objects are initialized in C++ through constructors. A constructor has no return value and the same name as the class.

// C++
 class Person {
 public:
 Person() {} // Constructor
 };

In Swift objects are initialized through initializers. An initializer has no return value and its name is init.

// Swift
 public class Person {
 public init() {} // Initializer
 }

Invoking a constructor or an initializer is similar.
Note: I am only pointing out the syntax here, how the objects are being allocated is different.

// C++
 Person p;
 // or
 auto p = Person();
// Swift
 var p = Person()

Constructors and initializers can be used to set initial values for fields.

// C++
 class Person {
 int _age;
 public:
 Person() : _age(25) { }
 };
// Swift
 public class Person {
 var _age : Int
 public init() { _age = 25 }
 }

Fields can also be inline initialized.

// C++
 class Person {
 int _age = 25;
 public:
 Person() { }
 };
// Swift
 public class Person {
 var _age : Int = 25
 public init() { }
 }

Constructors and initializers can take parameters. Note: I am only showing that parameters can be passed, and not discussing implicit vs explicit parameters in Swift.

// C++
 class Person {
 int _age;
 public:
 Person(int age) : _age(age) { }
 };
// invoke
auto p = Person(25);
// Swift
 public class Person {
 var _age : Int
 public init(age : Int) { _age = age }
 }
// invoke
var p = Person(age: 25)

Constructors can invoke other constructors in the same class.

// C++
 class Person {
 int _age;
 public:
 Person() : Person(25) { } // invoke the below constructor
 Person(int age) : _age(age) { }
 };

Initializers can invoke other initializers in the same class.

// Swift
 public class Person {
 var _age : Int
 public convenience init() {
 self.init(age: 25) // invoke the below initializer
 }
 public init(age : Int) { _age = age }
 }

Constructors and initializers can invoke their base class’s initializers or constructors.

// C++
 class Person {
 int _age;
 public:
 Person(int age) : _age(age) { }
 };
class Student : public Person {
 int _id;
 public:
 Student(int age, int id) :
 Person(age), // invoke base constructor
 _id(id)
 {}
 };
// Swift
 public class Person {
 var _age : Int
 public convenience init() {
 self.init(age: 25) // invoke the below initializer
 }
 public init(age : Int) { _age = age }
 }
public class Student : Person {
 var _id : Int
 public init(age: Int, id: Int) {
 _id = id
 super.init(age) // invoke base constructor
 }
 }

Order of initialization

Now that we have seen the basics of the initialization syntax of C++ and Swift, let us get to the interesting part, order of initialization.

In C++ the order of construction is determined by the class declaration.

Objects are initialized from the top down in the inheritance heiarchy. Base classes first left to right then data members top to bottom. Given the following code:

// C++
 // Given the following classes
 class Person {
 int _age;
 public:
 Person(int age) : _age(age) {
 // constructor code
 }
 };
class Student : public Person {
 int _id;
 public:
 Student(int age, int id) :
 Person(age), // invoke base constructor
 _id(id)
 {
 // constructor code
 }
 };

When an instance of a Student is created.

auto s = Student(25, 1001);

The constructor for Person will be executed first. It will initialize _age and execute any code in the constructor body. Then _id will be initialized and finally the the code in the Student constructor will be executed.

This is straight forward single-phase construction that works well in C++.

In Swift initialization is done in two-phases.

Two-phase initialization takes a different approach. Instead of completely initializing the base class protion of the object, i.e. initializing the data as well as executing the initialization code, before initializing the sub class protion, it separates the initialization of the data from the initialization code.

The first phase, initializes the data starting with the sub class fields and working its way up to the base class fields. The compilier will enforce this so that you cannot call super.init before all sub class fields have an initialized value and you will not be able to invoke any methods on the sub class until super.init finishes. The second phase then executes code that can now safely access any fields because they are guarenteed to be initialized.

// Swift
 // Given the following classes
 public class Person {
 var _age: Int
 public init(age: Int) {
 _age = age
 // initialization code
 }
 }
public class Student : Person {
 var _id: Int
 public init(age: Int, id: Int)
 {
 _id = id
 super.init(age)
 // initialization code
 }
 }

When an instance of a Student is created.

var s = Student(25, 1001);

First the field _id would be initialized, then super.init would be called, then _age would be initialized. This would complete the first-phase and the second-phase would then execute any initialization code.

Swift uses two-phase initialization to prevent code from accessing the memory of an object before it has been initialized which might happen if you were to call a method (which is dynamically bound by default) from a base class initializer.

// Swift
 public class Person {
 var _age: Int
 public init(age: Int) {
 _age = age
 print() // dynamically bound
 }
 public func print() { println("age: \(_age)") }
 }
public class Student : Person {
 var _id: Int
 public init(age: Int, id: Int) {
 _id = id
 super.init(age) // invoke base initializer
 }
 override public func print() {
 super.print()
 println("id: \(_id)")
 }
 }

Because _id is initialized before super.init is invoked the following code:

var s = Student(age: 25, id: 1001)

Prints out:

age: 25
 id: 1001

In C++ dynamic binding is not fully set up until construction is complete so the above example in C++ would result in the print function on Person being called instead of the print function on Student.

// C++
 class Person {
 int _age;
 public:
 Person(int age) : _age(age) { print(); }
 virtual void print() const {
 std::cout << "age: " << _age << std::endl;
 }
 };

class Student : public Person {
 int _id;
 public:
 Student(int age, int id) :
 Person(age), // invoke base constructor
 _id(id)
 {}
 void print() const override {
 Person::print();
 std::cout << "id: " << _id << std::endl;
 }
 };

In C++ _id is not initialized before Person’s constructor is invoked but the v-table used for dynamic binding is also not fully set up so Person::print gets called and the following code:

auto s = Student(25, 1001);

Prints out:

age: 25

Note: In Java _id would not be initialized and print would be dynamically bound allowing the access of uninitialized memory.

Two-phase initialization can be implemented in C++ and there are many discussions on the pros and cons of its use. This post is not concerned with addressing those. The intention of this post is to simply point out the difference between C++’s build in initialization mechanism and Swift’s.

 

Michael Kennedy

A Python enthusiast and an entrepreneur. Host of Talk Python and Python Bytes podcasts, founder of Talk Python Training. Python Software Foundation Fellow.

Tags: , , ,

2 comments

  • I actually find the C++ to be more readable than the Swift.

    The Swift Syntax seems bipolar to me. On one end, they are clearly trying to be a terse and simple language compared to the likes of ObjectPascal/Delphi and [especially] Visual Basic 14. On the other hand, they are trying to be descriptive with this sparse syntax. It just does not read well to me.

    I think the C++ declaration syntax is more straightforward:

    [const] { }; makes a ton of sense, even when read right to left. That’s actually reasonably self-documenting…

    var or let… types after semi-colons. It just not as readable, IMHO.

    I started Self-Study on C++. I tried Swift first (I have a Mac Desktop and a Windows Notebook) but ended up returning the books I bought and switching over because I don’t like the Syntax. C++ is going pretty well.

    The way books have switched from teaching procedural C techniques (as C++) to Standard/Modern C++ is one of the greatest things to happen in this industry, Lol.

Submit a comment