As I’ve said before, functions are my favorite building blocks. We can treat them as blackbox abstractions. We don’t have to care about what’s inside, only about what it receives as argument and what returns as output.

Image for post

We can define a function called inc that takes a number as an input and returns a number as output.

When a function is pure it will always return the same output if we always provide the same input. This implies something interesting: inc will always return a number.

It is pretty common to add constraints (or validations) to the inputs received by a function.

// divide :: (number, number) -> number
	const divide = (a, b) => {
	  if (b === 0) {
	    throw new Error('Cannot divide by zero')
	  }

	  return a / b
	}

Note: If you don’t know what’s up with the divide :: (number, number) -> number check this first.

The function divide takes two numbers and if the value of the second argument is 0 it will throw an exception. This breaks our pure model. This function won’t return a number every time we invoke it, even worse; sometimes it will break the flow of execution!

Image for post

We must make sure our functions not only don’t throw, but they always return a value.

The more outputs, the better

We could, instead of returning one type of output, we could return two. One representing the result, and other representing an error.

When I say return two value types I don’t mean both at the same time, but that the function could either return one or the other. Ptss… this is called foreshadowing.

Let’s modify our function inc.

	// inc :: number -> number | Error
	const inc = (x) => {
	  if (typeof x !== 'number') {
	    return new Error('Only numbers, pls')
	  }

	  return x + 1
	}

Our function inc now returns either a number or an error and the visual representation looks something like this.

Image for post

inc returns either a number or an error

Our function inc takes a number and returns either a number or an error.

If we wanted to consume our function inc we would do something like the following:

	const result = inc(2)

	// it's an error
	if (result.message) {
	  // handle error
	} else {
	  // use your value
	}

This extra code is no different from a try/catch block of code. So this extra code shouldn’t be an “issue” at the moment.

#functional-programming #software-development #javascript

Thoughts on Railway Oriented Programming — JavaScript
5.75 GEEK