# Basics 22 - Inline Functions

%[https://youtu.be/pHXPFHSFI00] 

# A Simple Case... Not Really

Let's take a simple example:

```plaintext
let add x y = x + y

let result = add 1 2
```

So far so good. We created a function named `add`. Since no type declarations are used, we assume that `x`, `y` and return value are all generic types. We can use this function as long as `x + y` is possible. Now, let's try this:

```plaintext
let add x y = x + y

let result = add 1 2 // No problem
let result = add 1.0 2.0 // Compiler error... expects int
let result = add "1" "2" // Compiler error... expects int
```

This is unexpected. `add 1 2` is working fine, but `add 1.0 2.0` and `add "1" "2"` are not.

Similarly, try this:

```plaintext
let add x y = x + y

let result = add "1" "2" // No problem
let result = add 1.0 2.0 // Compiler error... expects string
let result = add 1 2 // Compiler error... expects string
```

Roughly the same, but this time `add "1" "2"` is working fine, and others are not.

# Type Inference is not Generics (not always)

It took me a long time to realize the following:

1. The ***first come, first served*** nature of F# compiler
    
2. The absence of type declarations doesn't always translate into generics
    

When the line of code `let result = add 1 2` is encountered (where `1` and `2` are `int` values), type inference assumes `add` function is `int -> int-> int`.

In the other example, when `let result = add "1" "2"` is encountered (where `"1"` and `"2"` are `string` values), type inference assumes `add` function is `string -> string -> string`.

To complicate the matter, let's try this now:

```plaintext
let apply f x = f x

apply (printfn "%A") 1 // No problem, 1
apply (printfn "%A") 1.0 // No problem, 1.0
apply (printfn "%A") "1" // No problem, "1"
```

Everything works fine... duh!

Now what happens when `apply (printfn "%A") 1` is encountered? Isn't `1` an `int`, and shouldn't the parameter `x` of `apply` be marked as `int`?

# Generics and the Burden of Generalization

Let's revisit the `apply` function:

`let apply f x = f x`

What's the intent here:

1. Create a function called `apply`
    
2. Takes 2 parameters `f` and `x`
    
3. Call `f` with `x`, and the return value of `f` is the return value of `apply`
    

Pay attention... there is no uncertainty or ambiguity anywhere as long as `x` can be passed to `f`. This is what I call the ***Burdern of Generalization***. The caller has to make sure `f` can be called with `x`.

Now, let's go back to `add` function:

`let add x y = x + y`

What's the intent here:

1. Create a function called `add`
    
2. Takes 2 parameters `x` and `y`
    
3. Do `x + y`, and return the result
    

Pay attention again... do you notice any uncertainty or ambiguity? There is no way to ensure that `x` and `y` can be added. You can call `add` with any values... `int`, `float`, `int option` and whatnot. If `+` was a universal operation (`+` for any 2 things), there was no problem. `+` is a context-sensitive operation. `+` for `int`, `+` for `string` and `+` for `student` (user-defined record or discriminated union) are completely different ideas.

When `let add x y = x + y` is encountered, F# compiler is in wait and watch mode. It's waiting to see what follows... as soon as `let result = add 1 2` is encountered, type inference stitches everything together.

This is what I call the case of the ***Unresolved Burden of Generalization***. There are 2 ways this issue can be solved:

1. Constraints
    
2. Inline Functions
    

Constraints in generics require a dedicated article. So more on constraints later.

# Inline Functions

Inline functions are created with `let inline`:

`let inline add x y = x + y`

Inline functions are expanded and integrated into the calling code.

```plaintext
let inline add x y = x + y

let result = add 1 2 // let result = 1 + 2
let result = add 1.0 2.0 // let result = 1.0 + 2.0
let result = add "1" "2" // let result = "1" + "2"
```

There is no actual call to `add` happening here. Everything is expanded in line. With inline functions, there is no generalization required.

If you have reached so far, congratulations.

Keep reading!
