The "high order" Cornucopia

Bah... before I could finally understand what "high order functions"[1] are, why should I care about them and why now I can't live without them, whenever I read about them everything was polluted with abstract diatribes about so-called anonymous functions, joint-smoke types of union strikes of whatever, male bald pattern matching, monads, trinity processors, conduits and...

Wait. Wrong game.
... but I don't mind staying here for a while ( ͡° ͜ʖ ͡°).

You know that's not my style.
I won't bore you talking about "code expresiveness", "mathematical correctness of whatever", "function purity" and all that kind of sissy shit only people addicted to Starbucks care so much about[2], so let's jump into the fire.

I'll show you first what they are useful for and then I'll let you fall in love with them while I conveniently get an emergency call from home, so I leave you to get to know each other better ( ͡° ͜ʖ ͡°).

A real life struggle

I've already warned you this day would come, so I hope you listened and did your part.

Anyway, this is a quite common ocurrence in mods:

for all items in inventory
  do something
end

Let's see how three different mods would use that template for (if they were coded in Typescript).

Legacy of the Dragonborn:

let i = player.getNumItems()
while (i > 0) {
  i--
  const item = player.getNthForm(i)
  AddToMuseumDisplay(item)
}

Easy Containers:

let i = player.getNumItems()
while (i > 0) {
  i--
  const item = player.getNthForm(i)
  TransferMarkedItems(item)
}

Recycle Bins of Skyrim Redux:

let i = chest.getNumItems()
while (i > 0) {
  i--
  const item = chest.getNthForm(i)
  Recycle(item)
}

I could have gone over, and over, and over... but those three should suffice.

Let us review one of the maxims of computer programming:

Don't reinvent the wheel

Try not to repeat code.

Did you spot repeated code above?
Of course you did! You are not an stupid idiot.

Everything boils down to this:

let i = ObjectReference.getNumItems()
while (i > 0) {
  i--
  const item = ObjectReference.getNthForm(i)
  DoSomething(item)
}

Typescript wouldn't let us write something like that, so we must fix it.

But before doing so, let us remember/learn some programming basics.

Don't reinvent the wheel

You should put inside a function all code you know you will repeat over and over.

And since we know we will repeatedly do the same while cycle over and over, we put it inside a function.

function ForEachItem(o: ObjectReference, DoSomething: function){
  let i = o.getNumItems()
  while (i > 0) {
    i--
    const item = o.getNthForm(i)
    DoSomething(item)
  }
}

"WHAT THE FUCK??? ARE YOU USING A FUNCTION AS AN ARGUMENT FOR ANOTHER FUNCTION??? IS THAT EVEN POSSIBLE???"

Yes, it is.
At least, it's totally possible in Typescript (sorry, Papyrus users).

Enter the "High Order" functions

From now on I'll just abbreviate them as "HOF".

I was tempted to call them Hoff, but you kids won't know the real meaning of "epic" even if it hit you in your face.

Info

HOF are just functions that accept other functions as parameters, or can even return new functions.

But last example was bad Typescript syntax. We need to fix it so Typescript knows what we want to do:

// I put each argument in its own line for making it easier to read
function ForEachItem(
  o: ObjectReference,
  DoSomething: (item: Form | null) => void
){
  let i = o.getNumItems()
  while (i > 0) {
    i--
    const item = o.getNthForm(i)
    DoSomething(item)
  }
}

That was a valid Typescript function and now we can rewrite all examples above:

// Legacy of the Dragonborn
ForEachItem(player, AddToMuseumDisplay)
// Easy Containers
ForEachItem(player, TransferMarkedItems)
// Recycle Bins of Skyrim Redux
ForEachItem(chest, Recycle)

Warning

Notice how all function calls are using the function name but not () after it.

If you used ForEachItem( chest, Recycle(item) ) it would have been like telling Typescript, "Use the results from the Recycle function".

But you don't want to use the results from that function; you want to use that function.

Are you starting to see why HOF are such a big deal?

If you made functions like that, you will never have to write while loops ever again!

Tip

One of the biggest and most common sources of bugs are loops (for, while...) because they have so many moving parts.

By using HOF, you can extract the cycling part from your algorithms and concentrate on what really matters.

What's best: if you write a function with a loop that is guaranteed to work, now you know you have no need to check the looping part when bugs arise.

Tip

Less things to debug means it's easier to make more robust mods.

Hell, you can just put your HOF in some library and use it whenever you like if you know your looping function works as expected.
I certainly did that[3].

Declaring function arguments

Let us get back to our function:

function ForEachItem(
  o: ObjectReference,
  DoSomething: (item: Form | null) => void
){
  let i = o.getNumItems()
  while (i > 0) {
    i--
    const item = o.getNthForm(i)
    DoSomething(item)
  }
}

I know you wondered what the hell is this (item: Form | null) => void crap.
Well, it's the way we tell Typescript DoSomething is a function.

Function types need to be declared the same way you do for other types, like string, number, Actor, Form...
The only difference is that function declarations are a bit more complex, since functions may have arguments and may return values.

Function signatures

Function types are recognized by their "signature".

Two function signatures are considered equal if the type of each of their arguments and the type of the value they return match.

HOF accept/return functions based on their signature.

This means that a HOF asks you to declare function types by their signature, so you any time you call it you must provide a function argument that has the structure the HOF expects.

Passing a function (as an argument) with a wrong signature makes the same sense to Typescript as passing a string to a number, so it won't even compile.
Hell, a wrong signature is as different to Typescript as a string is different from a function; types simply don't match.

Anyway, let us dissect DoSomething signature by first analyzing the basic structure of the most simple signature possible:

() => returnType

This shit means, "A function that returns a value of type returnType".

Easy, right?

() => void

This means "A function that returns a void".
In human language: "A function that returns nothing"

I was tempted to make a joke about The Void, but my dad jokes level isn't yet so damn high.

What about all the other shit, item: Form | null?

Well:

If we put everything together:

DoSomething: (item: Form | null) => void

"DoSomething is a function with an argument called item of type Form or null, and returns nothing".

Tip

I suggest you to get acquainted with function declaration types and translate to human language every single one of those you encounter, so you get practice doing that.

Otherwise, anonymous functions and more complex HOF can get really messy.

You may be wondering why I put item: Form | null instead of just item: Form.

Well, I did it because most Skyrim Platform functions that return a Form, may return a null as well.

Typescript compiler will complain about some stupid bullshit like "Form is not compatible with Form | null, ni ni ni" if you did something like this:

function ForEachItem(
  o: ObjectReference,
  DoSomething: (item: Form) => void
){
  let i = o.getNumItems()
  while (i > 0) {
    i--
    const item = o.getNthForm(i)
    DoSomething(item) // ERROR
  }
}

That's because ObjectReference.getNthForm itself is declared as:

getNthForm(index: number): Form | null;

Which means you should be aware of the very real possibility of that function returning a null; a possible null you need to deal with.

Note

Typescript has many safeguards against null values and Skyrim Platform obligues.

This means most of the time you will be writing SkyrimClass | null in your function signatures.

Before ending this section:
I know what your inquisitive mind is wondering; and the answer is yes.
DoSomething could have been a HOF itself.

DoSomething: (item: Form | null, DoSomethingElse: () => string) => void

A practical example

I won't write again here the code for ForEachItem.
My point should have come across long ago and I told you not to repeat code, so let's get straight into some concrete example on how to actually use it, since the examples I used have no concrete implementation on how they work.

This will be a function that just prints the name of each item[5].
With just a bit of work this can be used for making an UI that lists all items in some inventory.

I trust you understand you can make this as complex as you want.
You can easily print only the names of items containing some word, only print Armor items, only favorited items... I'll let you play with that.

function PrintItemName(i: Form | null){
  printConsole(i.getName())
}

function PrintWeaponValue(x: Form | null){
  if(!Weapon.From(x)) return
  printConsole(x.getGoldValue())
}

function PrintHi(_: Form | null){
  printConsole("Hi")
}

ForEachItem(Nazeem, PrintItemName)
ForEachItem(bossChest, PrintWeaponValue)
ForEachItem(player, PrintHi)

Did you notice how not naming item the argument for either PrintItemName, PrintWeaponValue or PrintHi won't raise an error?

That's because the item name in DoSomething: (item: Form | null) => void is mostly used for documentation purposes.
It wouldn't care less if the passed function decided to call it Bob.

Note

The only thing a HOF cares about a function passed to it as argument is that argument types for that function match with what the HOF expects.

Variable names aren't part of a signature; only their types are.

In fact, it is customary to call _ variables you don't care about because you won't use them, like I did in PrintHi.

I know that last thing sounds stupid, but in later articles we will see it has some uses.

Wrapping up

We have just barely scratched the surface of what you can do with HOF, but I hope at least I sowed the seed of curiosity on you.

I mean... it sounds kind of big deal to me to never ever again having to pollute your code with yet another fucking for loop that only distracts you from what you are supposed to be doing.
Just imagine what other kind of boring and distracting cruft you can get rid of with them.

In the meantime, I suggest you to learn about map, filter and reduce.
That shit is awesome and will make you to fall in love with HOF forever.

Oh, excuse me.
I got an emergency call from home. I'll see both of you later ( ͡° ͜ʖ ͡°).


  1. This is the first article in a series of "Functional Programming" ones.

    I don't like to get on hype trains, but I'm also smart enough to catch on when something is useful and actually delievers.

    I think "functional" ideas are way better for doing mods than "Object Oriented Design", which tends to overcomplicate simple things and make the planning stage of a program a real nightmare.
    Some "Functional Programming" concepts will totally aid in our quest for doing better porn mods, and that's why I'll talk about them.

    As usual, I'll keep it as simple, straight-forward and pragmatical as possible.
    You don't need to know/care about lambda calculus and understanding obscure mathematical concepts just to create a goddamn mod. ↩︎

  2. Ok... all those things are Serious Business and really useful in practice, but you already know how I am ¯\_(ツ)_/¯ ↩︎

  3. You will notice both the function in the library and the one I put in here are the same.
    This shows you how can a simple, unassuming function be totally used in production code thanks to HOF. ↩︎

  4. An Skyrim Form. ↩︎

  5. Meh. I got carried away and put three functions instead. ↩︎