Monday, September 5, 2016

Rollup "map" from an Array to a Dictionary

I've often found myself doing work taking a sequence (usually an Array) of things and turning them into a Dictionary (key -> value mapping). Whenever I find myself doing something similar a few too many times, I find it's time to write a bit of reusable code, hence rollup.
rollup is three functions to provide an interface for taking a sequence of items and making a dictionary out of them. Here are the three cases I handled:
  • A) I have a sequence of Keys, so I provide a function that maps each Key to a Value to fill out the dictionary.
  • B) I have a sequence of Values, so I provide a function that maps each Value to a Key to fill out the dictionary.
  • C) I have a sequence of Things, so I provide a function that maps each Thing to a Key & Value to fill out the dictionary.
Let's see how we might use each.
A) I have the Keys
someKeys.rollupKeys({ (key) in valueForKey(key) })

B) I have the Values
someValues.rollup({ (value) in value.keyAttribute })

C) I have some Things
someThings.rollup({ (thing) in (thing.keyAttribute, thing.valueAttribute) })

Why does (A) use the name rollupKeys() for it's function? The short answer is compiler confusion. Let's use a simple example and say I want to use String as the type for both keys and values. The compiler would have no way to tell which version of rollup() I was trying to use because the function from a Key to a Value is identical to a function from a Value to a Key in this case. So I'm choosing to make life simpler for (B) as that is the more frequent usage of this rollup() behavior in my own experience.

Here is the current code for Rollup as a Gist, and some important Note/Warning below…


I should also note, one flaw with these as they are is that they do NOT gracefully handle situations where you have more than one Value for the same Key. These functions, as written today, will return the LAST Key->Value mapping seen by going thru the sequence in order, so you would lose any other values that shared a common key. Arguably, a better interface might be to have these functions be called flatrollup() and use rollup to map things into a dictionary of type [Key: [Value]] to handle the overflow problem. Then you would get an array of multiple items whenever you provided multiple values for the key. If you make such code, please tweet me and I would be happy to share your solution.

Wednesday, March 30, 2016

Money Conversion - More Swifty

My reaction to this post Swift: Money with Phantom Types is that functions like convertGBPtoEUR() are not very Swifty.

While Phantom Types are an interesting concept, I feel that some well-placed extensions can make for some better results.  Here are the two motivating examples of using currency conversion:

To get to the point, here is what I end up with for usage:

I find this syntax to be much clearer, and we can get the money in the currency we want more directly, without having to write a unique function call for each currency we add to the system. So, let's look at how we get here.
The key function driving this is:
func convertTo(Money.Currency) -> Money?

Here, Money is a struct containing both Currency and Amount as in the original post. And I add the convertTo() function as an extension. This one function uses a switch on the tuple of the previous and next currency enum values to define all the possible conversions we need to support. This is a great advantage to us as a maintainer of this currency conversion code, for a few different reasons:
  • We have one function point to do the currency conversion work we want between currencies here.
  • When I add a new currency, I will get a compiler error on this switch statement so I'm forced to add the exact code that I should add when a new currency enters this system
With the function-per-currency-conversion paradigm and Phantom Types that have no correlation to each other, I can add a new currency and get zero compiler errors. That may seem nice, but it makes it very simple for someone new to this code (including my future self who has forgotten) to add a currency and not realize that I should write more conversions for that new currency.
This function can be even more powerful if I make it return Money instead of the optional Money? and thus require myself to provide conversions between each of the currencies that I support.

Ok, so hopefully I’ve made a good case for the centralized convertTo() function. Now that we have that in place, we can add the syntactic sugar to convert values with dynamic vars. Here’s the code for that:

Here, I add three extensions. First, convenience constructors from Int and Double to allow me to make a Money value from a simple number like: 5.USD or 4.72.GBP
Second, conversion from one Money currency to another, yielding syntax like 5.USD.GBP to get a Money value for 5 US dollars in Pounds. Again, by making convertTo() return Money instead of the optional, then these conversion extension vars to Money will return an optional.

UPDATE: Looking at some of the responses to Natasha's original post, I came across this code by Dave Delong https://gist.github.com/oisdk/569de8286f9f706749b7d0668836706a#gistcomment-1737857 which has some similarities to my own solution proposed here. I like that he is using a currency factor on each to ensure that each currency can be converted between without any special logic, though I'm far outside my domain of expertise with currency conversion. I have some strange feeling that it may not always be simple enough to peg everything against the US Dollar, that exchange rates might actually vary uniquely. Of course, depending upon how sophisticated the need for currency conversion in practice would drive how sophisticated the code needs to be.

Hello, world!

My name is John Haney and I make apps. I want to help pay it forward and help you learn some Swift code so you can make your first app, or make better apps!

I run the Year of Swift meetup in Saint Louis and hope to see you there too.

I plan to post a few different things here, among them:
  • January, February and March Playgrounds from Year of Swift. These are my introduction to programming concepts using Swift.
  • Swifty solutions.

Friday, January 15, 2016

Happy New Year - January Playground, page 1

This post covers most of the content from the Year Of Swift Playground for January 2016. You'll have the best experience using the playground within Xcode on a Mac, but this blog post will still include the information.

Happy New Year!
This is the beginning of your journey to learning to program in Swift. You will start with learning about a bit about how Playgrounds work, and we will go over some of the basics of how you can move information around.

First, let's start with some simple things about how Playgrounds work. Any code you type in, the Playground will run that code and you'll see any results on the right-hand side.

So, you can type in numbers:
1
2
3

You can do some math, yay math!
1 + 2 + 3

Now, programmers like to use letters for variables (you'll learn about them in a minute), so for multiplication, you need to use the asterisk *
3 * 4
3 * 4 * 5

You use / to divide, and - to subtract, of course. Try them out here, maybe start with 4 / 2 - 1:

And if you remember some of your math, you can group things together with parentheses, these guys: ( )
4 / (2 - 1)
(4 / 2) - 1

Now, we can make a group of numbers in order. In Swift, we call this is called a Range. Here, we have the numbers counting up to 4. 1, 2, 3, 4.
1...4

But look, did you see that over there -->

The Playground runs this and shows the Range as 1..>5 ..> means start from the left number, and include everything less than the right number. So they are really the same value, even if you write it one way, and the Playground writes it another way. 2 + 2 is still the same as 4, right? Well, try it?
2 + 2 == 4

We use two equal signs as a way to check if two things have the same value. If you write 2 + 2 = 4, you will get an error. The red stop sign with an exclamation mark on the left!

You need to get rid of the error or else anything after the first error in your Playground won't be run at all! The Playground is a little picky like that. You must not have any errors. When you write programs, we call errors like this compiler errors. If you have a compiler error, then your program won't be able to run at all. That's why they get marked in red with the big stop sign. Anyway, how do we fix that error up there? Well, you can change the = to ==, or you could "comment out" the line of code with the error. To turn anything into a comment, you put // in front of it. Whenever the compiler, I mean the Playground, sees //, it ignores whatever else you write on the same line. In fact, it turns the // and anything behind it a different color. We programmers like different colors for different parts of our code that we write. It helps us know what the compiler, or Playground, thinks about the code we wrote.

3 + 4 // this part is just a comment that is ignored
// And this whole line is a comment. Don't mind me, I'm just a really long comment line.

Ok, so you were promised that you would learn about variables. Well, here you go… Variables are a place to keep stuff. Since we've been dealing only with numbers so far. We will start by keeping track of some numbers. To make a variable, you use either let or var. When you use let, you are making a constant. That means that you can put one value into it only!
let numberOfDaysInJanuary = 31

Ahh, only one equal sign this time. See that? When we use only one equal sign, we are assigning a value to something. This goes from the right to the thing on the left. So we just put the value 31 into numberOfDaysInJanuary. Time for another...
// let numberOfDaysInFebruary = 29 // This is commented out, because it won't work. You can read about this next.

Well, when John Haney wrote this, it was for the year 2016, so February has 29 days this year. But, February will only have 28 days most years. You shouldn't make this one a constant because it's not ALWAYS the same value. How about this?
let numberOfDaysInFebruaryInALeapYear = 29
let numberOfDaysInFebruaryInANonLeapYear = 28

Ah, fixed it. Two constants! Now we can handle how many days are in February. Ok, time for March. I'm going to get a little tricky with this one:
let numberOfDaysInMarch = numberOfDaysInJanuary

See, January and March have the same number of days, so I can just assign March the same number of days as January. I can even do a little math if I want for April:
let numberOfDaysInApril = numberOfDaysInMarch - 1

One less day than in March. That works too, it got 30. See it, over there? --> So, I can keep going like this for the rest of the months, but I'm sure you get the idea. But, something is bothering me about the month of February. I really want to just have numberOfDaysInFebruary for the current year. So, you can update this Playground with the year here first:
let year = 2016

Ok, did you change it right up there? Good. So, to figure out how many days should be in February in this year, you need to make a choice based on whether or not this year is a leap year. What's the rule for leap years again? Something about being divisible by 4. But also not divisible by 200? Ok, that gets a little complicated and there are leap seconds too, but we're not going to worry about all of that because you just want to learn how to write code in Swift, right? Right. Ok, so let's just do the divisible by 4 part, and you and I will know that this isn't REALLY the leap year rule, but it's close enough for today.

So, how do we check if a number is divisible by 4? Great question, so glad you asked! We can use a special operator %. Who picked that? Not glad you asked, because I don't know. Anyway, this % returns the modulo of dividing the left number by the right number. Gosh, let's just look at a few examples, shall we?
4 % 4
5 % 4
6 % 4
7 % 4
8 % 4

So, if the left number IS divisible by 4, then the result is zero over there --> Ok, so you can make the choice yourself.
year % 4

Did that come out as zero over there --> If it did, then you use numberOfDaysInFebruaryInALeapYear If it didn't, then you use numberOfDaysInFebruaryInANonLeapYear You know, we could check if it came out to zero and then the Playground would give us a true or false instead. Let's do that for all of our examples too.
4 % 4 == 0
5 % 4 == 0
6 % 4 == 0
7 % 4 == 0
8 % 4 == 0

And for this year:
year % 4 == 0

Ok, great, now I've got either a true or a false for whether this year is divisible by 4. That's a lot closer to what I need. Wait, but you shouldn't make the choice yourself. We're learning to write code because we want the computer to make some of these choices for us. It's really good at math and making these types of simple choices. I mean, really good. Your computer makes thousands of little choices like this every day. So, how do we make a choice in Swift? We use an if statement. And here's the commented out version of it to start with:
// if year % 4 == 0 {
// // the year is divisible by 4
// } else {
// // the year is NOT divisible by 4
// }

Ok, so there's some stuff here to look carefully at. First, those squigly parentheses looking things { and } are funny. You want to call them curly braces? Ok, curly braces is what we will call them. Swift calls a set of curly braces a closure. any code inside a set of curly braces is grouped together and run together. The Playground still runs things from the top line down, and when it goes into a closure, it will still run those lines in order, from the top down, too. So, the "if" makes a choice between two things. Either the thing the "if" chooses from is true, or the thing is false. We call that "thing" the condition. And something that is either true or false, we call a boolean value. In Swift, they call them Bool for short. When the if condition is true, the first closure is run. When the if condition is false, the else closure is run. You don't have to put else or even have an else closure. A lot of times, it's enough to just do something special when the if condition is true, and not do anything when the if condition is false. For February, we do want to handle both if and else, or both true and false. Here's what that looks like:
let numberOfDaysInFebruary: Int
if year % 4 == 0 {
    numberOfDaysInFebruary = numberOfDaysInFebruaryInALeapYear
} else {
    numberOfDaysInFebruary = numberOfDaysInFebruaryInANonLeapYear
}

Ok, a couple of things to look at here. First, see that numberOfDaysInFebruary is a constant. We only set it once, but this time with the right value based on this year. Also, We did something funny with numberOfDaysInFebruary. We put : Int after it. What in the world is that all about? Well, in Swift, the Playground (or compiler) will try to figure out what KIND of variable you are trying to make, and it does a pretty good job of getting it right a lot of times. But, for variables where you don't give them a value right away, the compiler needs a little more help to know what type of value the variable is. Here, we are going to put in a whole number. One term for those is an integer. And Swift likes giving things a bit shorter names, so integers are just Int. Whenever you give something a type, you use the colon : to separate the name of the variable on the left and the type on the right. One last thing you should notice. There's only the one number on the right-side next to whichever line actually set the numberOfDaysInFebruary. The Playground doesn't ever run the other line of code this time. You can play around with changing the year and see which line of code is run instead.

Now that we've talked a little bit about types of variables, let's talk about a few other types you may need to use in your code. Double represents numbers that could have a fractional component. Numbers like 1/2 or 12.99 can be saved and used as doubles.

var priceOfMilk = 3.95
var priceOfCheese = 2.95
var taxRate = 8.25 / 100.0

Time to checkout!

var subtotal = priceOfMilk + priceOfCheese
var tax = subtotal * taxRate
var total = subtotal + tax

How much, just for milk and cheese?! Well, it sure would be nice if I could get a receipt for this order. Let's print out a receipt:
print("Haney Groceries")
print("---------------")
print("Milk: $3.95")
print("Cheese: $2.95")
print("")
print("SUBTOTAL: $6.90")
print("TAX (8.25%): $0.57")
print("---------------")
print("TOTAL: $7.47")

Now, I'd like to direct your attention to the bottom of the Playground window. You should see a triangle in a box on the bottom left. Click that to show (or hide) the Debug Area. If you don't find it the triangle in a box for any reason, you can also use the menus to choose "View" then "Debug Area" and "Show Debug Area" to show the Debug Area. Anything that is printed by calling the print() function will show up here. Does this look like a receipt you get at your grocery store? If so, maybe they have some really old computers, but I digress…

You must have so many questions. What's a function? Why do you use double-quotes? How come over there I can see a \n at the end of whatever I put into the print() function?

These are really, really great questions that we'll talk about more next time!

Summary We just learned about:
  • How the Playground works and shows you immediate results, right over there -->
  • You can do math in a playground, yay!
  • Variables and constants with var and let
  • if and if-else statements let you make a choice of whether to run some code or not.
  • print() is a function, and we want to know more about functions.
Next Playground page: Function Junction