I have this piece of code here:
Let’s talk about this for a minute. First, a prelude.
If you have been reading about programming techniques recently, you may have heard the term “functional programming” bandied about, often in articles talk about how it is the next obvious evolution away from Object Oriented Programming. This is because it is also a programming paradigm and you know… The grass is always greener.
This is not really about the differences between OOP and Functional Programming however, and I don’t like the buzz-wordy nature of the subject as it is normally discussed. Let’s be clear:
- Functional Programming is not a silver bullet
- It will not release you from the woes of OOP
- It may release you from some, and give you others
- It will give you new ways of thinking about and solving problems
- There is no reason to look at Functional and OOP as mutually exclusive, you can work in both paradigms inside the same project
That last point I think is one of the most important and is rarely discussed. Grabbing the first line off the Wikipedia page for both helps us with a very light explanation, “Object-oriented programming (OOP) is a programming paradigm based on the concept of “objects“, which may contain data, in the form of fields, often known as attributes; and code, in the form of procedures, often known as methods.”. Sounds familiar enough. Now for Functional Programming we get this, “In computer science, functional programming is a programming paradigm—a style of building the structure and elements of computer programs—that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data.”. There are some more notes in the rest of the Wikipedia article and every other article written that compares the two, but that stuff is for other works.
If that is the simplest explanation of what each paradigm is, notice they don’t really do the same thing at all? None of the critical components of one explicitly negates the other. If you imagine an OOP hierarchy as a tree of objects, with some inheriting pieces from the one that came before, and you intend to do some work with this system you can imagine Functional Programming as a pattern of implementing the “work” or computation sideways, across all branches of the tree at once.
Let’s not complicate that with any more theory for now. If you have issues or questions about this part, feel free to leave a comment and I’ll link you some more detailed documentation on this section.
Some Important Syntax
If there is anyone is still reading this who is not aware, we just released a game into early access on Steam! The name of the game is Radio Violence and is made with Unity. Since we’re working in Unity at No Sleep right now, examples for code are going to be in C#.
From Microsoft’s C# documentation, “A lambda expression is an anonymous function that you can use to create delegates or expression tree types.”. An anonymous function is one which has no name by which to reference it. Which often raises eyebrows and questions of “why would I even want that”. We’ll get there, this is what the syntax looks like:
A delegate is a type that works like a function pointer in C++ or C. It holds the definition for a method, and can hold methods that meet that definition, allowing you to store, add, and work with methods as if they are objects. Once a delegate type has been instantiated you can pass it as a parameter, and you can multicast to it (allowing it to call more than one method, so long as they meet the criteria for the delegate definition and have been added to the delegate object). This allows callback systems, particularly useful for long running methods, asynchronous callbacks, and Events. They look like this:
Now that’s cool, and we even saw how a lambda is used in a more life-like scenario. The use of delegate still seems trivial though, and it’s a little unwieldy. For convenience C# includes two more things that make it a little smoother to use.
Action and Func
At this point I am taking for granted you know how to use generics, or can gather what’s happening from the previous and ensuing examples. If not, please leave a comment and I’ll link documentation or maybe do another blog on that entirely. It’s a little out of scope for this one though.
Action and Func are delegates that follow commonly used signatures.
Action and Func let you define the object without explicitly defining the delegate first, because it’s understood that they generically take at most 4 inputs, and in the case of Action returns void, and in the case of Func, returns the last type given. We can repeat the delegate example used above, but just using action as defined here.
I’ve Lost Track of What We’re Doing Here
This has been a bunch of esoteric C# examples, I thought I was here for Functional Programming? What is all this?
To treat computation as the evaluation of math functions and avoid mutable, we’re going to need to use these things. To use them you must be able to read them.
Maybe you can read this now, but are are still pretty unclear on what it’s actually doing, or for, or how you might make some real use of it.
First Functional Programming Concept: Currying
Lot’s of “How To Functional Programming” starts with list comprehension, and recursion, and the importance of non-mutable data. Lot’s of these tutorials use a purely functional language like F#, Haskell, Elm… We’re using C#, and our context is gaming, and that stuff is great but we probably don’t care much or we’ll just use Linq for that. So we’re starting where most of those tutorials end, with Currying. Currying is the term for creating a function with pieces of all your desired parameters but not all of them, so that you can asynchronously get the rest later and execute later.
I almost did that early with this line:
action += s => Printer("Hello " + s);
Printer prints strings, s is a string, but calling action now prints
“Hello “ + s. You may find yourself wondering how that’s different than a regular function, and this one is not. It would be if I took it one step further though. What if I don’t know what I want to prepend on my string? I know I want to prepend, and maybe append, something. Let’s use filenames, they often come with some regularly structured relative filepath at the front, and almost always end with a filetype. But first…
A Trivial Example
curriedAdder does return something, it returns an
Action with the signature
Action<int>, so we can assign it’s results to another delegate later. It also takes a parameter, and int. We declare
curriedAdder as a lambda, in the form
y => stuff. The input parameter is y, the stuff returns yet another lambda. Our result, of the form
Action<int> also takes an input,
x. This gets us the expression:
y => x => Console.WriteLine(x + y);
Where y is the input for the function we call, and
x in the input for the function we return. The returning function will add
y and print the result, returning nothing. This let’s us quickly define two more little adder functions,
addsXTo10 (not to be confused with
subtract5. We call
curriedAdder with the amount we want to add to our input later, and it gives us a function we can assign to a convenient name for later use. These functions behave reliably since they all follow the same definition, and if we ever have an error in one we know just where to look. (You would expect an error in all of them, given the same conditions)
A Less Trivial Example
That filepath thing. That could even be useful depending on how you stored the results.
We don’t store the results in a useful way here, but the stuff in
listOfNamers is pretty interesting given how complex (not particularly, I hope) it was to make.
A Real Problem
With A Review
This returns a function which takes
T and returns
void, given a collection (list, array, etc.) which holds type
T objects, and a function which takes type
T objects and returns a
This function runs the inner input through the function which returns a
bool (also known as a Predicate), and if the predicate returns true, that value is added to the list supplied in the currying function. The types all match by design.
Why Do I Use This?
- You have a fairly large collection of data, let’s say some few thousand elements at a minimum
- Each element has an unknown and potentially large, changing number of filter-able criteria
- You need to make subsets of your collection
- You might also not know how many, or on what exactly, until runtime
That sounds gross. It also is more common than some might think; at least parts of that are true. Usually the worst part seems to be true anyways, the part about not knowing how many times or with what criteria we’re going to be doing this until runtime. Using currying we can move the creation of functions into something that happens at runtime, and only when certain conditions are met. Using multicasting and the properties of delegates, we can flexibly add and remove custom logic after the program has started. This let’s us make our subsets of n items from a large list, on m criteria, and not spend half our lives programming all the if statements.
How Do I Use This?
Without any if statements as it turns out. You have classes that need knowledge of certain subsets, and you have a thing that holds the main list. During startup, or in whatever initialization phase you need to do this in, any class that needs a subset let’s the holder of the list know:
- The criteria needed for an element to be in this subset (the predicate)
- The collection it should put that subset into
We’ll use a list of
ints for the example, because they’re easy and sortable. Feel free to make the object collected as complex as you need.
Hopefully you followed this far and didn’t doze off before now. Hopefully you learned something, maybe you have questions. If you have something to say about this material or any questions about it, please comment below. If you don’t want to have a public discussion but have questions about this you need answered, you can also message me personally.
Also, please leave a comment if you liked this style of informative post, and give a suggestion about what else you’d like to hear about.