Showing posts with label tuple. Show all posts
Showing posts with label tuple. Show all posts

Tuesday, June 30, 2015

Use Tuple types to model data

To use sqlite.swift with Swift 2, see the Create a Data Access Layer with SQLite.Swift and Swift 2 post.

A couple of weeks back I wrote a blog post on how to create a data access layer using SQLite.swift.  You can see the post here.  In one of the projects that I am currently working on, I wanted to create the data access layer as I described in that post because I know how well it worked from previous projects.  For this particular project however there are several tables that only have a couple of columns which means I needed to create a number of classes in the data model layer that contained only a few of properties. 

It seemed like a waste to create all those classes which only had a couple of properties so I started wondering if I could use tuples instead of classes to model my data.  I was unsure how modeling data with tuples would work but I decided to give it a try.  I found out that they really worked well. 

In this post I will explain how we could use tuples to model our data and then I will show how I would replace the data model classes from my previous post with tuples.  If you have not read my previous post about creating a data access layer with SQLite.swift, you can read it here.

What are tuple types

A Tuple type groups zero or more values into a single compound type.  Tuples can contain values of different types which allows us to group related data of different types together.  There are many uses for tuples and one of the most common is to use them as a return type from a function when we need to return multiple values.  The Void return type is actually a typealias for a tuple with no values.

Using tuple types to model our data

When I say that I want to model our data what I am referring to is grouping related data together is a single structure.  As an example if I want to create a class name PersonClass to model the information for a person the class may look like this:

class PersonClass {
    var firstName: String
    var lastName: String
    var age: Int
   
    init(firstName: String, lastName: String, age: Int) {
        self.firstName = firstName
        self.lastName = lastName
        self.age = age
    }
}

In this class we define three properties for our person and we also create an initializer that will set these properties.  This is quite a bit of code to simply store data.  If we wanted to create a typealias for a tuple named PersonTuple which models the same data, it would look like this:

typealias PersonTuple = (firstName: String, lastName: String, age: Int)

As we can see it takes a lot less code to create our PersonTuple tuple as compared to the PersonClass class.  Creating an instance of the PersonClass class is very similar to creating a PersonTuple variable.  The following code demonstrates this:

var pClass = PersonClass(firstName: "Jon", lastName: "Hoffman", age: 46)
var pTuple: PersonTuple = (firstName:"Jon", lastName:"Hoffman", age: 46)

We could actually shorten the tuple definition as shown in the following code but I prefer naming the parameters to show what they mean (really personal preference).

var pTuple: PersonTuple = ("Jon", "Hoffman", 46)

We can pass tuple types within our code just like we would pass an instance of a class or structure.  In the following code we show how to write a function that accepts an instance of the PersonClass as the only parameter and a function that accepts a PersonTuple as the only parameter.

func acceptPersonClass(person: PersonClass) {
    println("\(person.firstName) \(person.lastName)")
}
func acceptPersonTuple(person: PersonTuple) {
    println("\(person.firstName) \(person.lastName)")
}

When we replace data modeling classes or structures with tuples our code can become much more compact and in some ways easier to understand however we do lose the ability to add functionality to our data model types.  Some, including myself, would argue that losing the ability to add functions to our data model types is a good thing because if we truly want to separate our data model from our business logic we should not be embedding business logic in our data model classes.

Replacing data modeling classes with tuples

Tuples weren’t meant to be used as replacements for classes or structures however if we create a typealias of a tuple type it can very easily be used to model our data. In the Create a Data Access Layer using SQLite.swift post we had two classes in our data model layer:  Team.swift and Player.swift.  The code for these two classes is shown below:

Team.swift
import Foundation

class Team {
   
    var teamId: Int64?
    var city: String?
    var nickName: String?
    var abbreviation: String?
   
    init(teamId: Int64, city: String, nickName: String, abbreviation: String) {
       
        self.teamId = teamId
        self.city = city
        self.nickName = nickName
        self.abbreviation = abbreviation
    }
}

Player.swift
import Foundation

class Player {
   
    var playerId: Int64?
    var firstName: String?
    var lastName: String?
    var number: Int?
    var teamId: Int64?
    var position: Positions?
   
    init (playerId: Int64, firstName: String, lastName: String, number: Int, teamId: Int64, position: Positions?) {
        self.playerId = playerId
        self.firstName = firstName
        self.lastName = lastName
        self.number = number
        self.teamId = teamId
        self.position = position
    }
}

Now to replace these to classes with tuples, all I really need to do is to create typealiases instead.  For this I crate a DataModel.swift class that contains the following code:

typealias Team = (teamId: Int64?, city: String?, nickName: String?, abbreviation: String?)

typealias Player = (playerId: Int64?, firstName: String?, lastName: String?, number: Int?, teamId: Int64?, position: Positions?)

I then deleted the Team and Player classes and was able to build/run the project as it was before.  We could additionally remove the typealias names from the find() and findAll() methods of the data helper classes.  As an example, the findAll() method from the PlayerDataHelper class looks like this:

static func findAll() -> [T]? {
        var retArray = [T]()
        for item in table {
            retArray.append(Player(playerId: item[playerId], firstName: item[firstName], lastName: item[lastName], number: item[number], teamId: item[teamId], position: Positions(rawValue: item[position])))
        }
        return retArray
    }
We could change this function to this:

static func findAll() -> [T]? {
        var retArray = [T]()
        for item in table {
            retArray.append((playerId: item[playerId], firstName: item[firstName], lastName: item[lastName], number: item[number], teamId: item[teamId], position: Positions(rawValue: item[position])))
        }
        return retArray
    }

However I think the code reads better if we keep the typealias name in the code.

I created a github site which contains the sample project for the “Create a data access layer using SQLite.swift with the changes made in this post.  The repository is located here (https://github.com/hoffmanjon/SQLiteDataAccessLayer).  I would like to know what others think of using tuples to model data.  Please leave comments below.

If you would like to learn more about Swift, you can check out my book on amazon.com or on packtpub.com.