# Classes and Structs

In Swift, there are four methods to create custom data types. We have already gone over two: `enum`s and `tuple`s! There are two left that are pretty similar: `class`es and `struct`s.

### Classes

Classes are just how you think of them in any other imperative language.\
Here's the syntax for a class:

```swift
class <Insert Name>: <Insert SuperClass>, <Insert Protocols to Confrom to> {}
```

Note: The `:` should only be present if there is a superclass or protocol to conform to. To see more about conformance, read the `protocol` page.

#### Fields

We're going to want to store data somehow. We use fields to do this. Fields are variables and constants that are stored within an object.

We have two choices when setting up fields. We can declare a type and force setup onto initializers or we can assign it. For constants, if we assign a value, it will be the same for all instances. Kind of... If we are literally doing the same thing every time, consider using a static variable/constant–a field that is stored in the class, not in objects. For fields that need to be distinct (you will come to understand this when we discuss when to use classes and structs later) then this it is valid to not use statics.\
For fields that cannot be setup at initialization, consider using an optional or implicitly-unwrapped optional. See optionals for more:

{% content-ref url="/pages/teTEwHPJb9tn9g7uM3hR" %}
[Optionals](/resources/swift-foundations/optionals.md)
{% endcontent-ref %}

#### Initializers

An initializer sets up all fields for an object that do not have default values and are not `nil`–optional fields that are not set up in an initializer will default to `nil`.

The syntax for an initializer is–this is a function and shares everything about them other than the `func` keyword:

```swift
init(<parameters>) {
    ...
}
```

Note for `Python` programmers: you do not need to pass self to initializers or methods!

When assigning or accessing fields and methods, `self` is implied. This means that you don't need to write `self.<some method or field>` unless there is a local variable with the same name.

Another note about initializers: You cannot reference `self` until you have set up all of your properties. I.e. you cannot call functions in your initializer until you have finished setup.

#### Default Variables

To define a default value for a field you have two options. The first is to create a default parameter within the `init` function. This allows for different default values depending on the manner of initialization. The other method is to, when declaring a variable, assign it. This makes the default variable the same no matter the method of initialization; however if it is a variable and not a constant, `init` functions can change this variable. There is no difference between the two choices other than style.

If all of your fields have assignments or are optional, you don't need an initializer.

#### Failable Initializers

This won't make much sense if you have not read optionals–in this case, skip this section, it's quite a rare case. Sometimes, the arguments that are passed to your initializer may not be valid. In this case, you may not be able to initialize an object. You can make a choice to either crash/raise an error or return `nil`–you can think of this as an optional initializer. In this case, you do everything the same as you would normally, except for the following:

1. Tag your initializer with a postfix `?`: `init?`
2. Return `nil` when the initializer fails

#### Convenience Initializers

You may find yourself doing a lot of the same initialization work over and over in different initializers. In fact, you may be sometimes initializing from different representations of the same data. In such a case, you may convert from one representation to another and then do the same initialization work. This is a lot of copy and paste–this is where a `convenience` initializer comes in handy. A `convenience` initializer allows you to handle this representation conversion and then call an initializer you have already written! You just need to do `self.init(...)` to call the other initializer.

```swift
class Person {
    
    // MARK: Fields
    var name: String
    var age: Int
    
    // MARK: Initializers
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    
    init(name: String, yearOfBirth: Int = 2002) {
        self.name = name
        age = 2022 - yearOfBirth // with rounding errors
        // all fields setup
        describe() // referencing self
    }
    
    init?(name: String?, age: Int?) {
        if let name = name, let age = age {
            self.name = name
            self.age = age
        } else {
            return nil
        }
    }
    
    convenience init(names: [String], age: Int) {
        self.init(name:
                    {
                        var name: String = ""
                        for i in names {
                            if name == "" {
                                name = i
                            } else {
                                name += " " + i
                            }
                        }
                        return name
                    }(), age: age)
    }
    // a more concise way would be to use `reduce`, but that's too advanced for this part of the course
    // for those that are interested, look at advanced array operations
    
    // MARK: Methods
    func describe() {
        print(name, age)
    }
    
}
```

#### Subclasses

To create a subclass of a class, all you need to do is add `: superClass` in the header.\
To implement the subclass you must be careful in your order of initialization. First, setup the new fields that are declared in your subclass. Afterward, call your designated `super.init`.

You may be familiar with the idea of overriding from other languages. This idea lets you modify functions, variable behavior, and initializers that are defined in the super-class. When looking for a method/field in an object, the lowest instance takes precedence. I.e. sub-class trumps super-class. To declare an `override` we use the `override` keyword. This is true for fields, methods, and initializers. If you `override` something, Xcode will handle adding the `override` keyword for you–or will let you know if you stopped this process.

```swift
class Noah: Person {
    
    // MARK: Fields
    var lastName: String // There are a lot of us, so we need to distinguish
    
    // MARK: Initializers
    init(lastName: String, age: Int) {
        self.lastName = lastName
        super.init(name: "Noah", age: age)
        describe()
    }
    
    // MARK: Methods
    override func describe() {
        print(name, lastName, age)
    }
    
}
```

### Structs

Structs are very similar to classes, so much so that we have an entire section dedicated to their differences below. If not stated to be different below, assume it has the same behavior as classes. To declare a `struct` instead of a `class` we use the keyword `struct`:

```swift
struct <Insert Name>: <Insert Protocols to Confrom to> {}
```

Generally speaking, you can think of `struct`s as a more rigid class. Remember how adding rigidity to variable types added for security and safety–this can be thought of similar. This rigidty comes in the form of memory management and a different form of inheritance (there are no substructs)! There is an alternate form of inheritance, but that is more of a topic for protocols. For times where you want your data to have a very specific memory setup (how the fields are setup), size, and explicit times with mutability, use structs.

#### Initializers

We don't actually ever need to define initializers for structs. Structs are aware of their fields, and if no initializers are specified, will construct an initializer for you that takes all of your fields as arguments.

```swift
struct Person {
    
    var name: String
    var age: Int
    
    func describe() {
        print(name, age)
    }
    
}
```

The above struct has an implicit initializer:

```swift
init(name: String, age: Int) {
    self.name = name
    self.age = age
}
```

You may find it useful to add extra initializers. You can do that just as you would with a class. If you add an initializer, you will lose the implicit initializer. You can define it yourself, so it doesn't matter. Just be careful when adding initializers that you handle the implicit initializer.

#### Mutating

As I mentioned earlier, mutability within structs is more rigid. Any function that changes a field must be declared `mutating`.

```swift
mutating func newName(name: String) {
    self.name = name
}
```

This allows for data type implementations to circumvent unintended side effects that may be present in classes.

### Objects

#### Instantiation

Instantiation is pretty dang easy. You're just calling a function with the data type being the name: `<Data Type>(arguments)`.

```swift
let noah = Person(name: "Noah", age: 19)
```

#### Accessing Fields and Methods

To access a field or method do `<instance>.<field or method>`

```swift
noah.name
// "Noah": String
noah.describe()
// Noah 19
```

### Extensions

We can factor out code to different areas of our file or even different files! We do this through something called an `extension`. As the name implies, we can build on types that have been given to us! Types like `String`, `Int`, and `Double` are all types that you can add functionality to!

All that we need to do is enclose our new features in curly brackets after the keyword `extension` and the type:

```swift
extension Person {
    
    var anotherDescription: String { name + ", " + String(age) }
    
    func getAge() -> Int {
        return age
    }
    
}

extension Person {

    func anotherDescribe() {
        print(anotherDescription)
    }
    
}
```

Note: You cannot create new variables unless they are computed properties or static.

You can even add conformances to types using extensions:

```swift
extension Person: Equatable {

    static func == (_ lhs: Person, _ rhs: Person) -> Bool {
        return lhs.name == rhs.name && lhs.age == rhs.agesw
    }
}
```

Note: `Equatable` doesn't actually require you to implement `==`, but you can if you want to! If you leave it alone, it will compare fields.

### Differences

Okay, so these seem pretty similar. Yes, structs are slightly more rigid, but that seems like a small change and not a big reason as to have two different ways to construct data types, so what's the difference?&#x20;

#### Reference Vs. Value Types

This is the real reason. Everything else is good to know, but not nearly important. Classes are something called reference types. This means that when you store an object in a variable you are storing a pointer to the object, not the object itself. This means you can store one object in multiple places, and if you change the object from one location, it will change the object from the other location as well because they are the same!

```swift
var noah = Person(name: "Noah", age: 19)
// id1: Person =
//    name: String = "Noah"
//    age: Int = 19

// noah: Person = id1
var noahsCopy = noah
// noahsCopy: Person = id1

noahsCopy.age = -1
noah.age
// -1: Int
```

Remember when I was talking about why `mutating` can be helpful in mitigating side effects, yeah that wasn't the only thing mitigating side effects. That being said, you may want this behavior! This is why classes exist.

As you may have guessed, `struct`s do not have this problem/feature. `struct`s are something called value-types. As the name implies, instead of storing references or ids, the data is directly stored. This means that if we assign a struct to a variable, it will copy its contents into a new `struct`. Aka. no side effects!

```swift
var noah = Person(name: "Noah", age: 19)
// noah: Person =
//    name: String = "Noah"
//    age: Int = 19

var noahsCopy = noah
// noahsCopy: Person =
//    name: String = "Noah"
//    age: Int = 19


noahsCopy.age = -1
noah.age
// 19: Int
```

This property makes `struct`s good for storing and passing data. If you're thinking MVC, your models will often be written as structs because you do not want changes in your data for the sake of presentation to affect your main store of data unintentionally.

A data type that you will use frequently that is implemented with `struct`s are `Dictionary`s aka hash maps.

#### Subclasses

There's one other big difference between the `class`es and `struct`s. `struct`s do not allow for subclassing. If you want shared behavior either use `class`es or `protocol`s.

#### Rigidity

I have already talked about rigidity, so I will keep this to new information, as this is an advanced part of this discussion that is not very important to note. For those of you that read the section on `indirect enum`s, you are familiar with the idea of compiler-time memory. `struct`s are no different. The compiler must be able to figure out the size of the `struct` at compile time. This means you cannot do recursion in `struct`s. I.e. let's say I have a type called `MyType`if myType has a field of type `MyType`, or `MyType?`, it must be a `class` and not a `struct`.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ios-course.cornellappdev.com/resources/swift-foundations/classes-and-structs.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
