Apple Reference, Articles, and Opinions

C to Swift - Article 0

The purpose of this series is to help people like myself who have been formally educated in C/C++ to write mostly low-level programs in very explicit, procedural ways, transition to using Swift for application development.

History

While it may not interest everyone, it is important to know how and why we got here with these two languages and it teaches us how and on what platforms these languages were meant to be used. In many ways, modern programming and software engineering began with C…

The C programming language was developed in AT&T Bell Labs for the purpose of running programs on Unix OS. Prior to C, many programs were still being written in very low-level assembly languages. One of the key goals of C was to make a language that did not necessitate the knowledge of the underlying architecture to the programmer. For example, in order to write a program for a computer, you had to be familiar with it’s ISA or Instruction-Set Architecture. A program snippet for a macOS app today might look like this, assuming it’s running on Apple Silicon

		mov r2, #0  		
  		mov r0, #0 
	top  	lsrs r1, r1, #1  	
  		adc r0, r0, #0  	
  		add r2, r2, #1  	
  		cmp r2, #32		
  		blt top  		

The code above counts the number of 1’s in register r1 and stores that number in register r0

Even with knowledge of the ARM ISA, this very simple program is not something easy to read or figure out. Comments help, but you probably would not have many people writing any kind of application for your platform other than wacko computer engineers.

Enter C, where the program above can be written like so

int num = 0, ones = 0;
for (int i = 0; i < sizeof(int)*8; i++) { 
	if (num & 1) { 
		ones++;
	}
	num >>= 1; 
}

Beyond making source code more readable, another goal of C was to make programs more portable. All you have to do is write a complier for the C to target the ISA of your system and all C programs will now run on any system that implements that architecture.

While this is a step above Assembly language, a C programmer still needs to be familiar with other low-level systems such as memory management. This has led many people to call C a mid-level language, where low-level would be assembly and high-level would be a language such as Swift or Java. In 1989 C became an ANSI standard and is today one of the most popular programming languages in the world.

About 25 years after the standardization of C, Swift is announced at Apple’s Worldwide Developers Conference to replace Objective-C, the previous language used to develop applications on Apple platforms. Craig Federighi of Apple best summed up the goal of Swift by posing one question at WWDC 2014

“What would it be like if we had Objective-C, without the baggage of C?”

Yes, he said "baggage!" As a computer engineer, I love C. I don’t mind the frustrations of dealing with memory management, or seg-faults, or the ridiculously long errors you get for missing a semicolon. However, I know that I am in the minority, because it would seem that among computer scientists, C is a language for computer engineers, embedded systems engineers, and masochists.This has led to the popularity of languages like Python, JavaScript, and Java.

Swift as a programming language is meant to be the balance of capability and ease of use for the programmer. With Swift, you can write code that is portable, fast, capable, and easy to read/maintain. Swift is meant to be the best of all worlds by having things software developers like such as type-inference, and a declarative syntax, but being fast and reliable like C/C++. It uses the same runtime and compiler Objective-C so you can run Swift alongside Objective-C and C/C++.

While you may have known this history already it's worth noting and reviewing it before moving forward. Apple did a great job with Swift and it is evident with the massive increase in popularity that it is an excellent balance of speed, reliability, and ease of use. Maybe a more appropriate name would've been Modern-C

In this series I will be using C with classes, AKA C++, to write my example C programs. Below are the two programming paradigms supported by Swift that are not supported by C++



Declarative Syntax


Swift supports both imperative and declarative syntax. As you begin transitioning from C/C++, I found this to be one of the hardest things to wrap my head around as declarative programming is a style of programming that is not as intuitive. I prefer more verbose ways of writing code because I see it as very explicit. This is a habit I have carried over from writing in C++. I often find myself writing both styles of methods in the same struct or class. Below is an example of the same function that quadruples the contents of each value in an array, one imperative in C++ and one declarative in Swift

C++ Imperative Example


std::vector<int> array = {0,1,2,3,4};
	
for (int i = 0; i < array.size(); i++)
{ 
	array[i] = array[i] * 4;
}

// array = {0,4,8,12,16}


Swift Declarative Example


var array = [0,1,2,3,4]
array = array.map{ $0 * 4 }

// array = [0,4,8,12,16]

As we can see from the above example, declarative syntax is much harder to read and requires a deeper knowledge of the syntax of the programming language, where it is pretty easy to read the imperative example and determine what it does. Arguments can be made for declarative syntax being more efficient if you trust that the underlying implementation (in our example the .map function) is better than your own.

What makes Swift declarative is that many of these methods are built into the data structures like the array, and the syntax is further shortened by the use of a closure using the $0 arguments. Declarative syntax is meant to ask for an outcome and abstracts the implementation of that outcome as much as possible. Of course, you can have a similar imperative implementation in Swift as the C++ example.

Protocol-oriented Language


Swift is a protocol-oriented language. If you have any familiarity with interfaces in Java, then Protocols are the Swift equivalent of interfaces. If you are only familiar with C/C++ and you are not familiar with what interfaces are, the equivalent in C++ is an abstract class. Essentially, it is a class composed of uninitialized properties and has one or more pure virtual functions.

When you inherit from an abstract class in C++, you must implement the pure virtual functions. The nomenclature in Swift is a lot better in this sense. A protocol is a set of rules that one shall comply with before completing or moving on to a task. For example, it is social protocol to place the napkin on your lap before eating a meal. As such, if your class will inherit from an Abstract Class in C++ or conform to a Protocol in Swift, you are agreeing to abide by the set of rules laid out by that Abstract Class or Protocol. C++ is object-oriented like Swift, but does not have a strict definition of an Interface or Abstract Class. It is up to the programmer to have knowledge of OO principles and learn the best practices. In this sense, Swift holds your hand a bit by defining protocols.

For a C++ programmer, it is a bit difficult to wrap your head around initially as the concept of inheritance is familiar, but the idea of multiple inheritance is usually not a good idea because you want to avoid diamond hierarchies. Inheriting from multiple abstract classes or protocols is however encouraged if your class (or struct in swift) can benefit from it. If you have ever wondered like I did, "If multiple inheritance is so bad, why does the language allow it?" - you may take solace in knowing it's not always bad.

See the example of a C++ Abstract Class below and a Protocol in Swift

C++ Abstract Class Inheritance Example


class Duck
{
public:
	float weight;
	
	virtual void quack() = 0;
	virtual void swim() = 0;
	virtual void display() = 0;
};

class Mallard : public Duck 
{
	Mallard(float w)
	{
		this->weight = w;
	}
	
	void quack()
	{
		std::cout << "QUACK!" << std::endl;
	}
	
	void swim()
	{
		std::cout << "SWIM!" << std::endl;
	}
	
	void display()
	{
		std::cout << "QUACK!" << std::endl;
	}
};

Swift Protocol Inheritance Example


protocol Duck {
	var weight: Float { get set }
	
	func quack()
	func swim()
	func display()
}

class Mallard: Duck {
	
	var weight: Float
	
	init(birdWeight w : Float) {
		self.weight = w
	}
		
	func quack() {
		print("QUACK!")
	}
	
	func swim() {
		print("SWIM!")
	}
	
	func display() {
		print("DISPLAY!")
	}
}

The implementation of either language is straightforward, but Swift encourages the use of protocols and I don't see too many C++ programmers using Abstract Classes, so I thought it would be a useful thing to point out early on before I dive deeper into Swift app development. Protocols, closures, and optionals have equivalent C++ counterparts, namely, Abstract Classes, Lambda functions, and Pointers. The latter two I will discuss in future articles.

That's it for my first article! I hope you enjoyed it and learn something. If you have any comments, corrections, or gripes, send a message here

With gratitude,
Jav Solo