Instruction

Procedural Programming vs. Object-Oriented Programming

You write computer programs to solve problems, and you usually break the problem into smaller parts, taking advantage of the “divide and conquer” principle. Object-oriented programming lets you think about problem-solving in a different way than procedural programming.

In procedural programming, you solve problems by designing procedures (functions) to work on data. Function calls and data can be anywhere in the program. If you need to change a function’s inputs or outputs, you must search the whole program and hope you find everything that you need to update. There’s a greater possibility of duplicated code — another source of errors when you make changes to the code.

In object-oriented programming, objects are the core component: They contain their own data and functions, and they interact with each other. You solve problems by designing objects and their interactions. You’re more likely to reuse code than to duplicate it, and you can more easily find bugs because you know exactly how and where data can be changed.

In the demo, you’ll take a quick look at the difference between procedural programming and object-oriented programming. But before you do that, take a moment to gain some foundational knowledge about structs and classes.

Structs & Classes

Object-oriented programming organizes app development around objects. Most apps manage objects like users and the items they use or create in the app — notes, to-dos, items to buy or sell, images or videos, social connections like followers or followed people etc. Here’s how you create objects:

  • Structs (short for structures) and classes are blueprints for creating objects. They encapsulate an object’s attributes and behaviors. Attributes are usually called properties, and behaviors are methods — functions that an object can call to perform a behavior.
  • An object is an instance of a struct or class: Each instance has actual values for its properties and can call its methods.

What’s the difference between structs and classes? You’ll explore this more in the next lesson, but here’s an overview:

  • Struct is a value type, like Int or Bool; an instance of a struct contains the actual values of its properties. If you pass a struct instance to a function, the function has a copy of that instance: The function cannot change the property values of the original struct instance. Your app’s memory stores a struct instance in the stack, which the CPU manages and optimizes, so it’s fast and efficient. You can instantiate structs without counting the cost.

  • Class is a reference type, so an instance of a class actually contains a reference — the location in memory where its data is stored. If you pass a class instance to a function, the function knows the location of its data and can change the values. Your app’s memory stores the data of a class instance in the heap and the reference — the location of the data — in the stack. Not only is there a two-step process to access the data, your app also needs to keep track of reference counts, or how many objects are holding a reference to this data. So instantiating a class is less efficient, and you don’t want to do it unless that piece of data is sticking around for a while.

Swift has a preference for structs and recommends you start by using a struct until you need some feature that’s only available for classes. A simple piece of data, like User or Note, is a lightweight object that your app won’t need forever. Typically, you’d model it with a struct.

Use a class when you want to create a shared, mutable state — that is, when you want a function to be able to change its property values. Another good candidate for a class is a data store, which is a collection of objects that you’ll use throughout your app.

If you’re keen to dive deeper into the distinctions between reference and value types in Swift, take a look at Reference vs. Value Types in Swift. For now, it’s time to proceed to the next section where you’ll explore the principles of OOP.

Principles of OOP

There are four fundamental principles that underlie OOP. Here’s what they are and how they can benefit your development process:

  • Encapsulation: A struct or class bundles an object’s properties and methods in one place. You can easily see what data and behaviors your app has to work with.

  • Abstraction: A struct or class limits access to an object’s data. Other parts of your app can interact with an object only through its public interface.

  • Inheritance: You can create subclasses of a class to share properties and methods. In a subclass, you can add properties or methods, or customize (override) the parent’s methods. Swift doesn’t allow multiple inheritance: A class can inherit from at most one other class.

  • Polymorphism: Your app can iterate over a collection containing parent and subclass objects, calling a method that performs according to the method definition of each subclass, or of the parent class.

You’ll explore the first two principles in the demo and the last two in a later lesson.

What’s Good About OOP?

So what are the advantages of OOP? Some reasons why OOP is a powerful tool in app development include:

  • Modularity: Encapsulation and abstraction make it easier to debug your app. All of an object’s information is in one place, and you know exactly how this information can change. It’s also easier to distribute work among team members, with each developer “owning” one or more object types.

  • Problem-solving: Modularity enables you to divide your app’s complexity into smaller problems that are easier to solve.

  • Reusability: Inheritance lets you reuse code. If you need to add properties or modify methods, you do it in only one place, and have all the subclasses inherit the change.

  • Productivity & efficiency: Reusable code, along with easier debugging, collaboration and problem-solving, make you a more productive and efficient developer.

Now, I’ll introduce a concept known as protocols in Swift and interfaces in Kotlin. Whichever name you use, this concept is a powerful tool for making your code flexible and reusable without relying on traditional inheritance.

Protocols/Interfaces

To model your data with inheritance, you must use classes. However, you can’t have multiple inheritance, and structs can’t use inheritance at all. Yet, Swift favors structs, and the Swift standard library contains many more structs than classes. How do you create reusable code without inheritance?

The answer is protocols/interfaces. For simplicity, we’ll stick to the protocol terminology moving forward.

A protocol defines a functionality or interface that a data type (struct or class) can conform to (adopt). And there’s no limit on how many protocols a data type can adopt.

Note: Protocols can’t hold data; they are simply a blueprint or template. You create structures or classes to hold data and they, in turn, conform to protocols.

You’ll learn about protocols in a later lesson.

See forum comments
Download course materials from Github
Previous: Introduction Next: Demo