A Fate Introduction
Fate is a programming language that targets the V8 JavaScript VM. It is a mostly functional language that provides first-class patterns, invocation guards, list comprehensions, flexible function application, and awesome concurrency.
The design of Fate is guided by one principle:
Data in a distributed system cannot be tamed
I started designing Fate because I was developing highly decoupled systems. These systems consumed JSON as their messaging payload, which provides great flexibility in implementation. But while JSON is ideal for transport and schema evolution, it can be difficult to process.
Fate attempts to address some of this difficulty by performing run-time dynamic checks on data via Patterns. These checks influence the way Fate programs process data. They also allow for clean code without excessive branching. (At least I think so)
Note: This guide is a work in progress.
A Concrete Example
Let's say you needed to calculate the NOx emissions for an OBD II reporting module. You could do it the obvious way:
def calculateVehicleEmissions(car)
if car.wheelsInMotion > 2
car.emissions
else
car.emissions / 40
end
end
But that's a lot of if
statements. Yes, one is too many. It also packs calculations for two different potential states into a single function. They will become more difficult to isolate should you need to hide the second calculation from government auditors. To correct this, you can break the function up and use a guard on its re-opened version.
def calculateVehicleEmissions(car)
car.emissions
end
def calculateVehicleEmissions(car) where car.wheelsInMotion <= 2
car.emissions / 40
end
That's better! Now if the EPA come to your place of business, you can simply delete the second function and they'll be none the wiser! On second though, that where
clause is practically like another if
statement. We've already established that we don't like those, so let's use an in-line pattern instead.
def calculateVehicleEmissions(car)
car.emissions
end
def calculateVehicleEmissions({ .wheelsInMotion <= 2 } as car)
car.emissions / 40
end
Better! But now you have the pattern matching for qualifying cars in a place where it can't be reused. Let's clean that up:
def calculateVehicleEmissions(car)
car.emissions
end
let VehicleUnderTest = ~{ .wheelsInMotion <= 2 }
def calculateVehicleEmissions(VehicleUnderTest as car)
car.emissions / 40
end
Done! The problem of vehicle emissions testing is now solved!
Important to understand is that VehicleUnderTest
is not a type declaration to be used during compilation. It is a Pattern, which is compiled into a Function. It is then executed as a predicate when your Function is invoked. If the Pattern doesn't match, the call falls through to the previous declaration, and so on. This is the Fate value proposition.
Getting Started
You'll need to install a version of Node.js greater than 4.0 before you can get started. The reason for this is that Fate's code generator targets ES6 features that older versions of Node won't support out of the box.
Assuming that you've installed Node, you can now install the Fate compiler as a global npm package.
npm install -g fatejs
This will link two command line executables into your PATH. The first is fate
. It is the command-line interpreter, and allows you to start Fate scripts directly from the command-line.
fate my_script.fate
fatec
is the command-line compiler, and allows you to convert Fate scripts into node.js modules. Those modules can then be required like any other node module. We'll discuss this tool in more depth later. For now, all you need to proceed is the fate
interpreter.