Intro to lenses in Swift: Immutability of objects
Tags: agilewebandappde, iosdeveloper, mobiledevelopment, programming
Published: 2019-05-10 07:31:03

---
title: Intro to lenses in Swift: Immutability of objects
published: true
tags: Agile web and app de,iOS Developer,mobile development,programming
canonical_url: https://apiumhub.com/tech-blog-barcelona/lenses-swift-immutability-objects/
---

To understand **lenses in Swift** , we should first review what we refer to when talking about **immutability** of an object.

We understand as an immutable object that object which can not be modified once it is created.

Its use gives us great advantages such as the reliability that our object has not undergone changes throughout the execution of the program, as well as its quality of **thread-safe** allowing us to access them concurrently without consequences.

 

## Intro to lenses in Swift: Immutability of objects

 

### The Lenses

The lenses provide an elegant way to update immutable states of an object. A lens, as the name suggests, allows us to **zoom** in a particular part of the structure of an object  
to obtain, modify or enter a new value.

We could define them as functional  **getters**  and  **setters**.

In the implementation of the lenses in Swift we will see that we have a whole object ( Whole ) and a part of this object ( Part ), they are the equivalent of the implementation with the generic **A**  and **B**.

```

struct Lens <Whole,Part> {
	let from: (Whole) -> Part
	let to: (Part, Whole) -> Whole
}

struct Lens <A,B> {
	let from: (A) -> B
	let to: (B, A) -> A
}
```

As we can see in the implementation, the **getter** of the lens returns a specific part of it, and the **setter** modifies a value and returns the whole object ( Whole ) with the new modified value, always talking about immutable objects.

 

### Case study

It will be based on a fictional case of a library.

```

struct Library {
    let name: String
    let address: Address
    let books: [Book]
}

struct Address {
    let street: String
    let city: String
}

struct Book {
    let name: String
    let isbn: String
}
```

First we are going to create our library object, based on the magnificent library of the city of Oporto,  _Livraria Lello_ , which served as an inspiration to J. K. Rowling for her Harry Potter novels.

```

let hp1 = Book(name: "Harry Potter and the Philosopher's Stone", isbn: "0-7475-3269-9")
let hp2 = Book(name: "Harry Potter and the Chamber of Secrets", isbn: "0-7475-3849-2")

let lelloBookstore = Library(name: "Livraria Lello",
                             address: Address(street: "R. das Carmelitas 144",
                                              city: "Barcelona"),
                             books: [hp1,hp2])
```

As we can see, the location of the city of the library is wrong.

If we wanted to change the city address of the object \* Address \*, which in turn is part of our library object, we could not change it by directly accessing the value \* city \* within our object, because we are working with completely immutable objects.

```

lelloBookstore.address.city = "Oporto" //Compiler error

```

To change the value of the city we will first create the **getter** and **setters** of the library.

 

## Getters y setters

```

extension Library {
    func getAddress() -> Address {
        return self.address
    }
    
    func setAddress(address: Address) -> Library {
        return Library(name: self.name, address: address, books: self.books)
    }
}
```

The method **getAddress** simply returns all the object **Address** and the **setAddres**  returns an entire object of **Library** with the new address.

We still have to create the **setters** and **getters** of the **Address** object in order to access the city attribute.

```

extension Address {
    
    func getCity() -> String {
        return self.city
    }
    
    func setCity(city: String) -> Address {
        return Address(street: self.street, city: city)
    }
}

```

Finally, we can change the value of the city of our library.

```

let newLibrary = lelloBookstore.setAddress(address: lelloBookstore.getAddress().setCity(city: "Barcelona"))
        
print(newLibrary.getAddress().getCity()) // Will print "Barcelona"

```

As we can see, our code has been composed in several levels.

We easily find cases like this with multiple levels of depth in our data structures.

 

### Lenses to the rescue

We will create a lens for the address attribute of our library, and another lens for the name attribute of the Address object.

To create lenses in Swift, we only have to indicate the types of input / output and define their getters and setters.

```

let addressLens = Lens<Library, Address>(
    get: { library in library.address },
    set: { address, library in Library(name: library.name, address: address, books: library.books) }
)

let cityLens = Lens<Address, String>(
    get: { address in address.city },
    set: { city, address in Address(street: address.street, city: city) }
) 

```

Now that we have the lenses, we will use them to try to repeat the same action we have done before, change the city of the library to Barcelona.

```

addressLens.set(
    cityLens.set("Barcelona", addressLens.get(lelloBookstore)
    ), lelloBookstore
)

```

The set of lenses returns a new library with the changed city, but our code is still less readable than using the getters and setters without lenses.

However, if we return to the code of our Lens, we can see that the output value of the first lens is the same input value of the second lens.

This gives us a clue, whenever we find cases where the output parameter of a function is the same type as the input parameter of another, we can benefit from the composition of functions.

 

### Function composition

We are going to define a **compose** function that will help us compose functions.

```

func compose<A,B,C>(_ lhs: Lens<A, B>,_ rhs: Lens<B,C>) -> Lens<A, C> {
    return Lens<A, C>(
        get: { a in rhs.get(lhs.get(a)) },
        set: { (c, a) in lhs.set(rhs.set(c, lhs.get(a)),a)}
    )
}
```

Now we can create a new lens that unites the previous two.

```
let addressCityLens = compose(addressLens, cityLens)
```

Using this new lens we can directly modify the city.

```

let newLibrary = addressCityLens.set("Barcelona", lelloBookstore)
newLibrary.address.city // Print Barcelona

```

 

### Operators

Let’s simplify it even more with the use of operators.

```

func * <A, B, C>(_ lhs: Lens<A, B>,_ rhs: Lens<B,C>) -> Lens<A, C> {
    return compose(lhs, rhs)
}
```

We see how using the operator we can now join the two lenses.

```

(addressLens * cityLens).set("Barcelona", lelloBookstore)

```

Now we can move the lens code inside their respective objects using their extension, just as we did with the getters and setters.

```

extension Library {
    static let addressLens = Lens<Library, Address>(
        get: { $0.address },
        set: { a, l in Library(name: l.name, address: a, books: l.books) }
    )
}

```

We would do the same for Address, and finally we could compose our lenses where we need them to get a deeper focus on our objects.

```

let newLibrary = (Library.addressLens * Address.cityLens).set("Barcelona", lelloBookstore)
newLibrary.address.city //Print Barcelona

```

If you are interested in receiving more tips for Lenses in Swift or movile development in general, I highly recommend you to subscribe to our monthly newsletter [here](http://eepurl.com/cC96MY). 

 

## If you found this article about lenses in Swiftinteresting, you might like…

 

[Functional Javascript: Lenses](https://dev.to/apium_hub/functional-lenses-in-javascript-1aa6-temp-slug-4094718)

[iOS snapshot testing](https://dev.to/apium_hub/ios-snapshot-testing-2i79)

[iOS Objective-C app: sucessful case study](https://dev.to/apium_hub/protected-ios-objective-c-app-cornerjob-successfull-case-study-89e)

[Mobile app development trends of the year](https://dev.to/apium_hub/mobile-app-development-trends-of-the-year)

[Banco Falabella wearable case study ](https://apiumhub.com/tech-blog-barcelona/banco-falabella-wearable-ios-android/)

[Mobile development projects](https://apiumhub.com/software-projects-barcelona/) 

[Viper architecture advantages for iOS apps](https://apiumhub.com/tech-blog-barcelona/viper-architecture/) 

[Why Kotlin ? ](https://dev.to/apium_hub/why-kotlin-language-android-why-did-google-choose-kotlin--639)

[Software architecture meetups](https://dev.to/apium_hub/apiumhub-software-architecture-meetups-in-barcelona-31df)

[Pure MVP in Android](https://dev.to/apium_hub/pure-model-view-presenter-in-android-1736) 

[Java vs Kotlin: comparisons and examples](https://dev.to/apium_hub/java-vs-kotlin-5a33) 

```
 
```

 

 

The post [Intro to lenses in Swift: Immutability of objects](https://apiumhub.com/tech-blog-barcelona/lenses-swift-immutability-objects/) appeared first on [Apiumhub](https://apiumhub.com).