Wednesday, January 11, 2017

Farm Systems, Darryl Philbin, and Swift Classes

Part of what makes the St. Louis Cardinals a special franchise is their farm system. St. Louis' farm system routinely produces starters and all-stars that make the Cards perennial contenders. Not too shabby for a small market team.

How do they do it?

The Cardinals establish a culture in St. Louis that they duplicate all the way down to Rookie ball in Johnson City, Tennessee. 

In our last post we discussed how we use structs to model data. We can also use classes to model data. But what are classes and when do you use classes instead of structs? Let's walk through those questions and, along the way, use baseball's minor league system as a coding example. 

What is a class?
Big Nerd Ranch's Swift Programming notes that like structs, "classes are used to model related data under a common type." 
And here's what classes do that structs cannot which Apple's Swift documentation points out:

  • Inheritance enables one class to inherit the characteristics of another.
  • Type casting enables you to check and interpret the type of a class instance at runtime.
  • Deinitializers enable an instance of a class to free up any resources it has assigned.
  • Reference counting allows more than one reference to a class instance.
Let's flesh those out some more.

  • Inheritance enables one class to inherit the characteristics of another. This is particularly helpful if we want to create classes for baseball teams as each major league team has a number of minor league affiliates under them that are similar, but different. For instance, once we create a BronxYankees class with such properties as wins, losses, and attendance, the AAA ScrantonYankees can inherit all those properties from BronxYankees as they'll need them too, and then add a property that is unique to Scranton such as, DarrylPhilbinBobbleheadNights. We'll code out an example shortly.
When deciding whether to use a struct or a class, ask yourself if you think you'll need to use inheritance or not. If you are sure that you will not need inheritance, a struct is probably all that you need. If you know you'll need inheritance, create a class. If you are not sure if you'll need inheritance in the future because you can't tell the future and aren't sure how what you're building is going to change over time, choosing class over struct will do a better job of covering your butt and making your life easier for the long run.

Why?

Because if you choose struct now, but then realize down the road that you now need a class you will have to go back and change all your struct files and where they are called in your main file which is, technically speaking, a pain in the ass.

Now back to what classes offer that structs do not:

  • Type casting enables you to check and interpret the type of a class instance at runtime. Why is this important? For a few reasons. First, type casting allows you to check the type of an instance. Once you know what type an instance is, whether it is a String, Double, or a custom type, then you know whether it handles integers, floating numbers, strings or a custom type. Type casting also allows developers to know what protocols the instance conforms to according to its type. In other words, once you know what type something is you'll know what you can do with it. In baseball terms, if you are a hitter and you know what pitches the pitchers throws, you'll have a better at-bat. 

  • Deinitializers enable an instance of a class to free up any resources it has assigned. Specifically, deinitializers free up memory resources which means your program can run faster and more efficiently. A full description of deinitialization is available here in Apple's documentation with a working example included, but, in short, deinitializers remove set values from instances of the class you created when they are no longer needed. In baseball terms, initialization is like a player being given a uniform and number when he first joins the team and deinitialization is like when he hands in his uniform to the team before retiring. 

  • Reference counting allows more than one reference to a class instance. Earlier we created a BronxYankees class from which the ScrantonYankees inherited properties. In this case, ScrantonYankees are an instance of the BronxYankees class. Thanks to reference counting not only can ScrantonYankees inherit from BronxYankees, but so can all levels of the Yankees' minor system (TrentonYankees, TampaYankees, CharlestonYankees, StatenIslandYankees, etc). 
Now let's build out a new Xcode project that makes use of classes and inheritance.

Open Xcode and double-click on "Create a New Xcode Project". Choose macOS as your template and for this project choose "Command Line Tool" before clicking "Next". Give your project a name such as, YankeesSystem, and make sure that the language is set to Swift before hitting "Next". Then choose where you want to save your work. It can be in a specific folder, on your desktop, or wherever else you want; hit "Create".

Xcode will then open. On the far left panel click on the "main.swift" file which will open in the center panel with some sample code in it some of which we'll remove in a minute.

Create a new file (File > New > File) and name it BronxYankees. It will save under the main.swift file in the far left panel as BronxYankees.swift. Enter the BronxYankees.swift file by clicking on it.

Let's create our class and define what properties it will have.




For this project and this BronxYankees class, we'll start with attendance, wins, and losses and give them all initial values.

Next let's make them do something. Specifically, let's have them print out, "The Yankees have 72 wins, 40 losses, and a current attendance of 2000000."


First, we need to add a function to our BronxYankees.swift file. In this case, it is our seasonUpdate function that plugs in the wins, losses, and attendance values thanks to string interpolation.

To make this function run, we now go back to main.swift and call the seasonUpdate function.

On line 11 we call the file where the BronxYankees class resides and set it to a new variable called bronx. On line 12 we call the seasonUpdate function from the BronxYankees file. This returns:


which shows up in the console.

If we want to recreate the Yankees farm system we'll need to setup the Yankees' AAA affiliate in Scranton. Now let's create a subclass that inherits the wins, losses, and attendance properties that we created for the BronxYankees class. To do this we need to create a new Swift file. Let's call this new file ScrantonYankees. This is what that will look like:


On line 11 we create the ScrantonYankees class and we make it inherit from the BronxYankees class (ScrantonYankees: BronxYankees). By doing that we don't need to create another round of wins, losses, and attendance variables: the ScrantonYankees class automatically inherits them from the BronxYankees class.

But the Bronx is the Bronx and Scranton is Scranton. They may have wins, losses, and attendance in common, but they are not exactly the same.

On line 12 we show how Scranton is different: Scranton has Darryl Philbin bobblehead nights at their games (I'm just making this up).


But what happens if we call the ScrantonYankees seasonUpdate function? This prints out to the console:


This is nice, but it just prints out the BronxYankees wins/losses figures before printing the ScrantonYankees property we created. But what if Scranton actually has 38 wins and 22 losses? How do we change that?

It takes a few steps, but we can do it. Let's go.

First, go into the BronxYankees.swift file. After the seasonUpdate function we are going to add three new functions that allow us to change the values of our attendance, wins, and losses properties. They will look like this:



Let's walk through these. First, use the func keyword to create a new function. Then we give the function a name, in this case, we use changeWins, changeLosses, and changeAttendance - all names that indicate what the function is going to do, that is, change the values of our different properties.

We then pass an argument (amount: Int) that indicates that what we will pass will always be an integer type. Then we drop a { to announce that we are about to define our function.

Within our curly brackets we define our function. In this case, we are saying, "the number of wins/losses/attendance will change by the integer amount that we pass as an argument." 

When done with the function we close it up with a }. One big step done, two to go.

But, you say, why can't we just go back to the main.swift file, invoke changeWins and changeLosses, plug in our integer arguments and be done with it? Good question. Let's try that and see what happens.


On lines 12 and 13 we told our program to replace the BronxYankees' 72 wins and 40 losses with 38 wins and 22 losses for the ScrantonYankees. But as we can see in the console, the program added 72+38 and 40+22 instead, which is not what we wanted.

Fortunately, we can fix this by initializing our properties in the BronxYankees.swift file. Here's what that looks like:


By initializing our attendance, wins, and losses properties we make them ready for use. When we tried to use them before initialization we could not change the initial values we gave them. Now through initialization we can and we will. But first, some more explanation of what's going on between lines 16 and 19.

Line 16: We use the keyword "init" to announce that we are going to initialize our properties. We then pass attendance, wins, and losses as arguments and state that they are all going to be of the integer type. We then open up some curly brackets where we'll define our initialization function (lines 17-19).

"Self" in Swift is not an easy concept and can get meta pretty quickly so what I will say here is this: On lines 12-14 we have attendance, wins, and losses for the BronxYankees. On lines 17-19 we have attendance, wins, and losses for other, future instances of BronxYankees subclasses whether that is for the ScrantonYankees, the TampaYankees, etc.

To that end, lines 17-19 say, "the value of our attendance, wins, and losses properties will be equal to what we assign them in the arguments that we pass, not the initial values assigned to attendance, wins, and losses for the BronxYankees."

It is important to note that Swift initializers do not return a value as our example above shows. There are no values there. Rather, they serve to prepare instances of a type for use later on which is what we'll do next.

First, let's go back to our main.swift file. Once inside that we need to call on our ScrantonYankees subclass (line 11) and then call the seasonUpdate function (line 12).


Next we have to pass our attendance, wins, and losses arguments and their associated values to ScrantonYankees. While it's true that attendance has nothing to do with our final statement, we cannot run the program without giving attendance a value. As you can see in the console, it doesn't show up anyway.

So, as usual, a discussion on one topic, in this case classes, spilled over into other subjects as they all work together.

On Deck: The discussion on classes and structs continues in our next post which will go over the difference between reference types and value types, another important concept to understand when deciding how you want to build your programs.

Tuesday, January 3, 2017

Mookie Betts & the Swift Struct Type

If you're organizing a pickup game of softball on the Fourth of July, then getting all the details right isn't a big deal because the game is most likely a one time thing among a group of friends more interested in having fun. Chances are people are not keeping stats. Although there is always that one guy...

But what if you are organizing all of Major League Baseball, 30 teams that each play 162 games over the course of a regular season? That takes some organization. Organization of schedules, of travel, of players, of stats, etc. And it's not just for one year, but for an uncertain number of years to come.



How do we organize that data? In computing, we model that data. What's a model? Good question.

According to Wikipedia, "Data Model is an abstract model that organizes elements of data and standardizes how they relate to one another and to properties of the real world entities." For instance, a data model may specify that a data element representing a baseball team comprises a number of other elements which in turn represent the size of the roster, the size of the team budget, and the owner of the team to it.

To visualize this, I think of an Excel database. The name of our data model is the name of the database ("Baseball Team") and the names of the elements are the names of the columns and rows (roster size, team budget, team owner, etc). 


Once we have our data model setup, we can run through large quantities of data or values much faster than we could if we did each one individually without a model. That is, in earnest, a general overview of data modeling which can get more complicated.

Question is, depending on what you're organizing, how do you want to organize your data? As we've discussed in previous posts, there are different ways to organize information in Xcode and with Swift. Enumerations are one way, structures (aka structs) and classes are others. In this post we'll focus on what structs are, when to use them, and what they do.

What is a struct?
According to the Big Nerd Ranch's guide to Swift Programming, "A struct is a type that groups a set of related chunks of data together in memory. You use structs when you would like to group data together under a common type."

So let's break that down. 

We've seen types before, usually strings, integers, and doubles or floating point types. In this case, a struct is a custom type that you can create to fit your needs as you create and organize information. In our case, we're going to create a Hitter struct that keeps tract of the number of hits and homers that a players has. We will organize information according to these custom parameters.

Unlike previous posts that we have written and executed in Xcode Playgrounds, this time we will need to create an Xcode project to properly play with structs. Why can't we use structs in a Playground? 

The main reason we need to create a whole new project rather than use a playground is that we write structs in one file, typically an ancillary file, and then call those structs from another file, usually the main file, that our code exists in. Projects allow us to create and access multiple files: Playgrounds do not.

Why can't we just put them all in one file? If we did, when it came time for the computer to run our program it would run everything, not just what it needed that instant and this would take longer to run. By putting some important information in a separate file we keep our program faster, leaner, and more efficient.

When to use a struct?
We wouldn't need a struct to publish the fact that Didi Gregorious had 155 hits and 20 homers in 2016 because it's just one line that we can write out rather quickly ourselves. But what if we build a site that listed the names of all the players in baseball and how many hits and homers each hitter had? Considering that there are over 600 hitters in Major League Baseball every year, it would take a long time to write those all out. This is where structs and their data models come in.

What can structs do?

According to Apple's own documentation, structs can do the following:


  • Define properties to store values
  • Define methods to provide functionality
  • Define subscripts to provide access to their values using subscript syntax
  • Define initializers to set up their initial state
  • Be extended to expand their functionality beyond a default implementation
  • Conform to protocols to provide standard functionality of a certain kind
Sounds great, right? Now what does that all mean? Let's break those down because they will also be true of classes.

  • Define properties to store values: If you define a property such a hits, then you can give that property a value such as 200 hits. And once something has a value, you can use that value. If you don't define hits, then you can't give it a value and you can't use that value.

  • Define methods to provide functionality: Once you have your properties such as hits and homers, you can create a method, say, a method that calculates what percentage of a hitter's hits are homers, by defining a method that calculates that figure. This is what I meant in the previous paragraph when I said once a property has a value then you can use it. This is an example of us using that value to calculate something else.

  • Define subscripts to provide access to their values using subscript syntax: According to Apple's documentation, subscripts "are shortcuts for accessing the member elements of a collection, list, or sequence. You use subscripts to set and retrieve values by index without needing separate methods for setting and retrieval." 

  • For example, we can create an array called stewartWins that contains the total number of wins Dave Stewart had in some of his years as a starting pitcher and then access specific elements in the stewartWins Array by selecting an instance by choosing its appropriate index number. 


         
In this case, we want to see index number 3 which returns 22 wins so we write     stewartWins[3]. We can do the same thing with dictionaries as seen in the second example above.

  • Define initializers to set up their initial state: Can you imagine a hitter coming to bat without wearing a number on the back of his jersey? That's like variables or constants not being initialized with values. There are times when it's OK for variables and constants to not be initialized, but it's also nice to have the option to initialize them which structs support.

  • Be extended to expand their functionality beyond a default implementation: In other words, structs are not static or set in stone, but have the flexibility to expand their initial functionality. In baseball-ese that means you might come into the league knowing how to throw a fastball and curveball, but you can always pick up a change and a knuckle-curve: You aren't restricted to just what you had on day one.

  • Conform to protocols to provide standard functionality of a certain kind: While this is a little vague, it's another way of saying that structs, in general, play by standard protocol rules. In baseball-ese, structs will be around the strike zone - they won't kill anyone or your program.



An Example of a Baseball Struct
OK. So let's create a new Xcode project and our own struct.


Open Xcode and double-click on "Create a New Xcode Project". Choose macOS as your template and for this project choose "Command Line Tool" before clicking "Next". Give your project a name such as, hitterStruct, and make sure that the language is set to Swift before hitting "Next". Then choose where you want to save your work. It can be in a specific folder, on your desktop, or wherever else you want; hit "Create".

Xcode will then open. On the far left panel click on the "main.swift" file which will open in the center panel with some sample code in it some of which we'll remove in a minute.

Create a new file (File > New > File) and name it hitter. It will save under the main.swift file in the far left panel as hitter.swift. Enter the hitter.swift file by clicking on it.

Under "import Foundation" let's create our struct and define what properties it will have.

In this case, let's look at the career numbers, through the 2016 season, for Mookie Betts.



What do we have here? First, we created a struct with the struct keyword. We then gave our struct a name, in this case, Hitter which is capitalized. That's important. Then we open up a curly bracket to define our properties. The properties are all variables, one for the player's name (name), hits, and homers.

In this case, we've initialized our variables by giving them values ("Betts", 443, 54).

Now let's create a function so we can do something with our struct. Let's have ours say, "Betts has 443 hits and 54 homers."



Using the func keyword we create a new function which we call printHitterDescription. We add the () in case we want to pass an argument later. We'll leave it empty for now as we have no need to pass any arguments. And then we open up a set of curly brackets within which we'll write our function.

In this case, our function is an example of string interpolation, a quick way to show what structs can do. print() is a function within the printHitterDescription function that will print whatever we write in the parentheses to Xcode's console, below and to the right of the center section. Here, we want it to say, "Betts has 443 hits and 54 homers." We plug in our properties on line 17 (name, hits, homers) where we need them so the values will print out.

Now that the struct is ready to go, we need to connect the main.swift file to the hitter.swift file so it can pull the data it needs to complete the printHitterDescription function. We connect the two files by calling the hitter.swift file from the main.swift file. Here's what that looks like:



See line 11? That's where we call the Hitter struct from the hitter.swift file. In this case, we call it by setting Hitter() to the myHitter variable.

Line 12 prints out our "Betts has 443 hits and 54 homers" statement to the console by running our printHitterDescription() function on the variable myHitter that calls the Hitter file.

That's what it looks like to run a single instance through a model. In a future post we'll run more data through it so you can how that works.


Challenge: Create a new project with two Swift files one of which contains a struct for pitchers that models pitcher names, games started, and quality starts and then Tweet it to me at @randallmardus.

On Deck: Classes and how Structs and Classes are similar and different