Whythefunc cover

Why the Func

OO

This is a code I used to write. [receiver doThis]; It’s a code a lot of us used to write. It’s the way we looked at the world. We looked at the world with OO and we sent messages to receivers. Sometimes our messages took arguments. And so we had colons in there too and sometimes we had multiple colons. But we programmed this for a long time because we came from the small talk world and it was all about sending messages to receivers and that’s the way OO worked.

Objective-C and Function Calls

We used this funny syntax with square brackets and colons and what you need to know is this was for us. You know, we made a big fuss about, we did it this way because this is the way the world works, but this isn’t the way the world works. This syntax, there’s nothing magical about it and the way we know this is underneath it all, objective C was doing this.


[receiver do: this
        with: that];
        
objc_msgSend()

Objective C was making a function call for us and these square brackets that we fussed about and you must send a message to receiver, that was just for us, to help us look at the world that had nothing to do with the computer.

This way of organizing things with OO, that’s the way we looked at it and so these objects had these properties inside of it, the state inside of it, and the idea was you were prevented from interacting directly with the state because that’s what C programmers did.

Functional Isn’t as Natural as We Think

So what we did was we provided these entry points and these were the methods that you would call and this is how you would change the state without directly changing the state. You would send a message to a receiver. You would find these extension points and you would send a message to a receiver and this is the way we pictured programming. And so that was OO.

We thought, well, in the world of Squeak, we would have these cars and if we wanted the car to move, we would have to send the car a message and so maybe we would have a steering wheel and the steering wheel would send the car a message to turn a certain way and now, with Swift, we’ve come so far, and now we control robots with our iPads instead.

We’re still sending these messages to these objects and that’s OO, or maybe in the case of these robots, because we don’t know how it’s implemented, maybe it’s procedural.

Maybe underneath it all, we’re using functional because we’re told that’s cool and if we don’t read books on Haskell, and if we don’t read Monads, well, we might as well be using square brackets and colons. So. We understand OO, so we don’t need to talk about that today and we understand procedural.

Functional isn’t as natural as we think it is and we talked about OO because that’s the way we look at the world but perhaps functional is the way we look at the world. And so you think about, when we introduce Swift or introduce Objective C or Java or anything, we always start with “Hello, World.” Because that’s the law.

And so in Swift, our “Hello, World”, is actually very unnatural for people to think about. This is a function that doesn’t take anything and doesn’t return anything. And we think that this is simple, and it’s simple in code, but conceptually, it’s very different than what we think a function is.

“Hello, Daniel”


func hello(_ name: String) {
    print("Hello, \(name)!")
}

We think a function takes something and gives you something, and here’s a function, that’s all side-effect. And so we say, well, once you understand that will do this and we’ll use an underscore because Swift lets us and it makes calling it very nice, I can say “Hello” quote “Daniel,” and it prints “Hello, Daniel,” but this still, even though we’re passing it a string, it’s not returning anything.

This is an odd sort of function if you’ve grown up, you know, in the world of mathematics at all and gotten through high school math. And so when we think of functions in math, we think a function is something that takes an element of the domain and maps it to an element of the range. And, you might want to follow that guy out the door if you like, because it’s gonna be more like that.

Last year, I showed you the first thing that was ever written on the board during my freshman calculus class was this. But it basically just says, “for every element of the domain, there is a unique element of the range”. The function takes something in the domain and gives you something in the range.

Mapping

If you give it the same input, it gives you the same output each time. You can’t give it a three and it gives you one value and you give it a three and it gives you another value. And that’s our notion of functions. It’s mapping from one thing to another. It can’t do this because the function is confused.

Get more development news like this

That first thing does it go to that top or does it go to the middle? This is okay. Two different elements can map, and that’s Y equals X squared, two different X’s map to the same square, that’s okay. But each X can’t be confused. And depending on where you were raised, your teacher might have drawn something on the board that looked like this and said it’s a function machine.

So I have my function machine and maybe this is my function. It takes an input and it has an output. I don’t print something to the consul, I’m returning something and so I’m taking in a string and I’m returning a string. This is a function that takes an input and returns an output and so when I put in the string Daniel, because I think that much of myself, it says “Hello, Daniel,” and it entertains me all day.

So that’s function and that fits our notion. It doesn’t take nothing, return nothing. It doesn’t have side effects, it’s this function that we group up with. It’s this function in the math sense, the way we learned it in high school algebra. It’s this function that has no side effects.

Testable, Repeatable

This thing that we’re afraid of when we program because we’ve mutated or we’ve changed states somewhere without realizing it and so we don’t want to mutate and if we don’t mutate, then we have something that is testable, it’s repeatable.

Let’s return to our car. And we might have this non-functional approach where I tell the car to move forward and there is so many problems with this. One of the problems is, I have this global car that sometimes, somehow I have a control of and I tell the car, “Hey, can you change your position?”

I’m reaching into the car and I know it has a position, but even more than that, I know that the position isn’t it because I can increment it, I’m manipulating this general thing and I just feel dirty.

This also has the problem that if I repeat it, I’ve moved my car by a certain amount, I’ve moved my car by a certain amount, I’ve given it the same input twice and I’ve gotten a different output, my car is somewhere different.

It’s very hard to test it, so we think, well, OO is all about objects. So I’ll create objects, but it’s Swift, so better than class instance, I’ll create a struct because I read a book somewhere that told me that. Now I’ve got a car object and I’m feeling virtuous and the car must have a position and I’m gonna change the position so it has to be a var.

Hope nobody looks at my code in code review and sees that var, but we go on and change the var so that my function has to be mutating and that feels kinda gross too.

Mutating Function


struct Car {
    let position: Int
    
    func forward(_ amount: Int) -> Car {
        return Car(position:  position + amount)
    }
}

I have this var, I have this mutating function, but I’m still sending a signal car instance to the method and saying, “Hey, you! My car dot move forward by this amount.” And that’s what we did in Objective C for so many years and we felt great because otherwise we were working with CG wrecks.

And so I’m moving it forward but I still have this testability thing. I take my car and I move it forward. And I move it forward again and I get different results both times. So I think, well, what if I made this a let? Instead of a var, I made it a let and instead of a mutating function, what if I returned a new instance of car? What if I didn’t move the car forward, but when I told the car, “Hey, move forward,” it said, “Okay, but you gotta use this car now.”

And so I create a new instance of car at that new position. And I feel really good about this code except trying to teach this to someone and telling them that’s the way the world works, every time you move the car forward, I’m just gonna give you a new car.

Somehow that doesn’t fit my notion of the world or in french. And so instead of this being a car, I think, well, what if this is a CarView?


class CarView: UIView {
    private var car: Car
    // some init
    
    override func draw(_ rect: CGRect) {
        // code to draw the car
    }
}

This is the representation of a car, this isn’t the car itself, and so now I have a class that’s CarView and the CarView has inside of it, a car. And that car is that thing that knows where it is and all I have to do is I have to draw that car and so I’m drawing where that car is and what the car looks like and I’m separating these things out and I’m feeling really good because I’ve taken this functional thing and it now belongs to this non functional thing.

And if I get rid of this notion that I have to be purely functional or OO, or I can’t talk to the kids at the party, I’m in good shape. And we do that, we say, “Are you really a functional programmer or not?

So we end up with this combination and I know this looks like the objects and properties, but I want you to look at this a different way. I want you to look at this as the mutating CarView on the outside that is keeping us from interacting directly with the functional, the non-mutating stuff on the inside.

This is wonderful because this inside is greatly testable. I take a car and I move it and I get a new car in this new position. I take that car and I move it a different amount and I get a different one. I move it the same amount, I’m always getting these testable, repeatable results and what I get on the outside is the mutating part, the part that interacts with each other, I get this combination that is this world and this looks a lot like the way we think of MVC, right?

Where our view controllers communicate with each other but the view controller hides the communication to the view. And the view controller hides the communication to the model and so it’s just a different way of organizing our code. Functional is for us, OO is for us, and sometimes the same problem demands different solutions in different parts of the problem.

We can wrap this beautiful hard shell around this soft chewy finish in the middle and just have a delightful candy. Non-mutating function, mutating around this functional core and the good news is, right? Because why does Haskell need Monads? Haskell needs Monads because nothing mutates, nothing changes and so they needed to introduce this thing so that we could capture this outside state, inside state, and changing things and communicating, and we don’t need that because we are not a purely functional language.

We Don’t Need Monads

In Swift, we go through these gyrations to figure out what all these mean from Haskell and from Skala and from functional programming, but we don’t necessarily need them. We’ve got classes and we’ve got structs and we’ve got these different things we can use for these different, as long as we keep the separation clear and we know when when we’re communicating with the outside and we know when we’re not. That’s when we can separate it.

And so someone says, but we have Monads. Optionals are Monads. The point isn’t that we don’t have Monads, the point is that we don’t need them. They aren’t needed in the system of Swift. And so Swift supports this functional paradigm, it supports this way of thinking of the world, but it’s not required. It’s not a purely functional language.

We have both structs and classes, we have lets but we also have vars, we have non-mutating and we have mutating and so the point is, Swift is just the best of both. It supports these functional ideas, but we’re not restricted.

We can’t be sloppy in every language, you know of course we can, in Objective C where you expose these things that are supposed to be private out by using categories or class extensions somewhere, so we can always cheat, but the idea is we should keep these things as separate as we can. And then no Monads are required and that of course means.

Teaching & Learning Functional Programming in Swift

I want to talk a little bit more about functional and teaching and learning functional programming, especially in the context of Swift. And when we hear about map, a lot of what we hear is you need map because for loops are bad. For loops aren’t bad.

The other thing that people get lost in is map is not a replacement for loops. We think it is after awhile, because every example we see is map in the context of array. And in the context of array, we’ve hidden this for loop inside of map.

So here’s a function. I’m on the iTunes store and I give you a string that I want to search for, and this returns a string that is the actual search term and so when I pass in string from: food and cooking, if you’ve ever searched on the iTunes store, it outs pluses in place of the spaces when it does it.

So, here’s just a function from string to string and the idea of map is, well, if I give you an array of strings, I want to lift this function, so this function from string to string, now I can give it a whole bunch of strings and it gives me back a whole bunch of strings.


extension Array where Element == String {
    func searchStrings(using f: (Element) -> String) 
                                                  -> [String] {
        var result = [String]()
        for entry in self {
            result.append(f(entry))
        }
        return result
    }
}

So we go through these gyrations again, although Swift 3.1, do you like the where element is string? Oh my god, I love that, we waited for that for years! And so this is only for arrays of strings and the case that we have an array of strings, I can now lift those two search strings, which takes this function from string to string and it lifts it to a functions that takes an array of strings and returns an array of strings, and we do what you think you do, is you go through this array of strings and you just map each entry in it over and that’s what map does for you.

This is my search strings method and so I give it all of my favorite things that I want to search for. And I pass it in like this. I say either search strings using string, or because it’s a trailing closure and I want extra points on Stack Overflow, I use dollar zero. But in either case, I get what I get when I map each one of them individually in my array.

Map for Array

This is what we think of in maps when we do map for array, is I have this function from A to B and I want to lift it to something that takes an array of A’s and gives my back an array of B’s. And the thing that goes from an array of A’s to an array of B’s is the map of F. And so more generally, I think, the map of F takes this lift of A, this array of A’s into this lift of B, this array of B’s. And so we’ll just keep saying this over and over in different context and map will just become completely clear to you.

So now when I map it either this way or when I map it using dollar zero, I again get the same results because map is built into the Swift standard libraries. But again, not only aren’t for loops bad, map does not replace for loops. And so to show you that, I want to do map’s and optionals.

Map and Optionals

Here’s a map with optionals. They’re my favorites. Kim’s favorites, well, she doesn’t have any favorites. And so it’s an empty array and what I’m gonna ask is, take Daniel’s favorites and get the first element but when you ask an array for the first, you get back an optional, because it might not have a first. You know, Kim doesn’t have a first favorite. I do. And so I’m gonna get an optional.

So if I say, “Get a string from danielsFaves.first,” this doesn’t work because string expects an actual element to type string and I’m passing it an optional string and so,, we if let it. And if we if let it, we get the right result because we’ve unwrapped the optional string and if we if let Kim’s, we don’t get anything because it’s nil, we don’t unwrap it, we just skip the if block.

So we want to be able to lift this function that went from string to string to go from an optional sting to an optional string. So I want to pause and share a dream of mine with you right now. We’ve got a function that maps from one type to another, say a string to an int. And I’ve got a function that maps from an int to a double.

Visual Tool

So I imagine this visual tool that lets me take these things and because this results in an int and this takes an int, I can snap them together and I can visually compose functions and I can build up this almost integrated circuit and just pipe things right through. And I can open this guy up and it’s a function from string to int, so I can put any function from string to int in it. And now that I’ve got this pipeline where I’ve matched up the ints and I’ve ended up with a function from string to double by composing them, oh my gosh, look at what I can do next!

I can say, well, I don’t want to give you a single string, I want to give you an array of strings. And so the result should be an array of doubles. So really, I’ve just wrapped this composition inside of a map. I don’t want to give you an array of strings, I want to give you an optional string, then I should get out an optional double. So I have wrapped this whole composed function in a map. That’s all map does, it helps me go from something of this type, to something of this type.

Optionals


extension Optional where Wrapped == String {
    func searchString(using f:(Wrapped) -> String) 
                                            -> String? {
        switch self {
        case .none:
            return nil
        case .some(let value):
            return .some(f(value))
        }
    }
}

I have my map and optionals and so, just like we extended array, I’m gonna extend optional, and now I take this function from string to string, this function that was inside here that I’m passing in, and I now result in a function that takes an optional string to an optional string the way we had an array of them to an array of them.

You can say no. I’ll just say it again. And so in this case, I’m gonna switch on self and if you’ve ever talked to functional programmers, they’re gonna say to you, “And it does the obvious thing,” which is so obnoxious. But the natural thing, let’s say, is if I give you a nil, you give me back a nil. There’s nothing it can do with it. And if I give you something that isn’t nil, you give me back something that isn’t nil.

This function mapped from string to string, and so if I give you an optional string in, and that optional string is nil, you give me back nil. And if it’s not, you’re gonna map it over. And so, you’re gonna take something that is some, and you’re gonna bind to whatever value I give you, and you’re gonna calculate F of that value and wrap it back up and give it back out to me as an optional and so it kind of is the natural thing.

It’s wrapping it back up and returning it to you and so if I say, take Danielsfaves, pick out the first element, which is optional, call searchString, now I’m calling SearchString on an optional using that function and I get food and cooking because it unwraps it, I’ve hidden the unwrapping. I’ve hidden the if let. I’ve hidden the switch the same way we hid the for, so map isn’t really about the for loop, it’s about that hiding the transitional from one state to another. And Kim doesn’t have any favorites, so when I try to see well, some or none, it’s none and so she gives me back nil and so map and optionals, same exact thing as map and arrays.

I’m lifting this function from A to B, to a functional from optional A to optional B, or the same general to the map of A, to the map of B. Okay? And so I can do this instead using map, just like we did for arrays, and when I do that for me, I get food and cooking, and then I do that for Kimmie, I get nil.

So, the shorthand that combines all of this is I’ve got a function from A to B and all map does is the map of F maps from the map of A to the map of B. And if you can say that with confidence, people think you know what you’re talking about.

Write Your Own Map

What gets you to the point that you actually do understand what you’re talking about, is when you write your first map for yourself. When you’re in a situation you say, “Oh, you know what would help here? A map!” And so, one example that you should do is an exercise I’ll show you quickly, but it’s worth doing ‘cause it’s not done for you in the Swift standard library, is the result type.


enum Result<Value, Error> {
    case success(Value)
    case failure(Error)
}

The result type before we had errors in Swift and now that we do some people still use this, the result type is generic in two variables. It either takes a value or an error and in the case that I succeed, I’m gonna give you back the successful value wrapped in the successful enumeration case and if it fails, I’m gonna give you back the failure case with the error in it.

It’s a lot like optional where the failure corresponds from the none case to the nil case and the success corresponds to the some case. And so, oh my gosh! If I’m gonna write something that maps from one result type to another, it’s gonna be result A comma error to result B comma error.

It’s gonna be error type on both sides just like it’s nil on both sides, but what’s different is, I’m gonna lift a map from A to B to a map from result A error to result B error.

Let’s extend result. And so result is generic in value and error and so I’m gonna have a function from A to B would be from value to whatever my target value is, and so I’m gonna end up with something that is a result of type target value error.


extension Result {
    func map<TargetValue>(_ f: (Value) -> TargetValue) 
                                -> Result<TargetValue, Error> {
        switch self {
        case .failure(let error):
            return .failure(error)
        case .success(let value):
            return .success(f(value))
        }
    }
}

And I’m just gonna do the same thing I did with optional, I’m gonna switch on self and if it’s a failure case, I’m gonna map the error across like we did with nil. And if it’s not, I’m gonna bind to the value and calculate F of that value and that’s what I’m gonna result in. And I went through this quickly, because I really do want to leave this as an exercise.

The problem with map, is you get to the point where you think, well, it’s always a container, it contains elements of type whatever. That’s what we say the same in it’s an array of A’s, it’s a optional of A, it’s a result of A value.

Isn’t a Container

I want to do another example that isn’t a container. This is a class of maps from double to something else. So I have a function from double to string, I have a function from double to URL, I have a function from double to anything. So this is generic in whatever the target is of the function. So the double is just a function from double to whatever the generic type is.

Here’s how I create an instance of that. I create times one through four to be something that will result in an array of doubles. I give it an X and it returns X times one, X times two, X times three, X times four. It returns an array of four elements. I give it this X and it returns an array of doubles.

So when you say, do times one through four of the double 5.2 it multiplies 5.2 times one, two three and four, that’s the result. Why would we ever do that? We wouldn’t. Just stay with me. Let’s do another one.

This time I want one that just prints out a description and so it takes a function from double to string, double to string and it just returns X dot description so the string representation of the double 5.2 is the string 5.2.

Now, let’s write a map for this type. The type of functions from double to something else. Just ‘cause it’s not a container. And so I’m gonna do that same lift. And so here’s what map looks like.

I’m gonna pass it, this function, from A to B just like we did in every other map. Every other map took the function from A to B. And remember, the result is I start with a function from double to A and I want to end up with a function from double to B. And so I’m just gonna compose it. I’m gonna do double to A, F takes me from A to B, and that composition gives me a map.

So my result is gonna be this function from double to B and the way I do it is I just compose F of double of B. If I get rid of self it’s completely clear. Okay. So, I always need the map from A to B, and so here’s a map from an array of doubles to an string. I’m gonna add all the doubles together and then print out the value. Add ‘em all up, print ‘em out.

When I do times one through four and I map displaySum and theDouble 5.23, it’s gonna add ‘em all up. Now, one times something, two times something, three times something, four times something, is ten times something, so, it was an easy thing to figure, we didn’t need to go through this. But the point is we lifted this map and the way we did it was we had a map from an array of doubles to a string, and so my map took this array of doubles, so the map of A, is a function from.

Map of Double

What does map of double look like? It’s a function from double to an array of doubles. And I also have this string. What’s map of string? It’s a function from double to string. And so I’ve lifted this map F from array of doubles to string to this horrible looking thing. A function from a function from double to array of doubles, to a function of double to string.

I have this map of A, which is a function from double to array of doubles, I have F, which takes a double to a string, and we talk about this, it makes the diagram commute. The going around is the same as going diagonally. “Ugh. We followed you for 25 minutes and we don’t know what you’re talking about now.”

The point is, map is another thing that people talk about in functional programming that isn’t nearly, once you start writing them for yourself, as mysterious. And it’s another way of hiding this functional core inside of this mutable, flexible outside shell. And so, that’s Why the Func?

Q&A

Question: You talked about map, which is one of the functional functions. But we’ve got a couple others, reduce and so on. The same principles apply? Or maybe you can comment on that?

Answer: So, the um, the short answer is, if you have a structure, like array, optional, that also supports map, you essentially have what we call a functer. So map is somewhat special. And the thing that I didn’t want to say out loud, but you’ve just forced it out of me, is if we have flat map, and another little thing, we essentially have what’s called a Monad, so it’s a lot less of a big deal than people think.

For convenience, we also have these reduce, and filter, and other things that are also very functional. The key to all of them is you don’t mutate the thing that you pass in. You pass in something, and what comes out the other end is some transformation, but you haven’t changed the thing you passed in. And so it’s the difference in array between sort and sorted. Are you sorting the original array, are you mutating it? Or are you giving me an array and giving me the results out the other end?

So what I’m hoping what you do in all of these functional things is separate the code that makes changes from the code that doesn’t. Gary Bernhardt in his boundaries talks about separating the thing that makes decisions from the thing that makes differences, that changes things. And so if you change this code out, you’re gonna find your code is much easier to maintain and our iOS code just really falls right into this. I know, people get really religious about, “It’s not MBC anymore, it’s MBVM, and it’s!” But it’s not. It’s just ways of separating into the things that change and the things that don’t. We just use different words for them. Okay.

Next Up: New Features in Realm Obj-C & Swift

General link arrow white

About the content

This talk was delivered live in June 2017 at AltConf. The video was recorded, produced, and transcribed by Realm, and is published here with the permission of the conference organizers.

Daniel Steinberg

Daniel is the author of the books ‘A Swift Kickstart’ and ‘Developing iOS 7 Apps for iPad and iPhone’, the official companion book to the popular iTunes U series from Stanford University. Daniel presents iPhone, Cocoa, and Swift training and consults through his company Dim Sum Thinking. He is also the host of the CocoaConf Podcast.

4 design patterns for a RESTless mobile integration »

close