Why infernu?

JavaScript Distilled

JavaScript, without the awful parts. Runs as-is, no need for compilation or translation.

Type Inference

Static types without annotations. Just write your JavaScript, infernu will fill in the types.


Type System

Safety First

Strong, expressive, static type system. No "any" type.


Example:
var x = new Date();
var y = x + 1; // this does terrible things
Infernu output:
:2:5:y:: Error: 
(...many more lines)
     Failed unifying:
         Date
     With:
         Number

Automatically Generic

Infernu finds the most general type, and creates type parameters appropriately.


Example:
function f(x) { return x; }
Infernu output:
f : a.(b -> b)

Robust Structural Typing

Row-type polymorphism keeps your code generic, while keeping track of the full type structure.


Example:
function getLength(obj) { return obj.length; }
Infernu output:
getLength : a.( { get length: c | b} -> c)

Read-only Properties

You can't override Math.PI, nor should you try. Infernu distinguishes - at the type level - between getting and setting a property.


Example:
Math.PI = 3.2;
Infernu output:
:1:1: Error: 
(...many more lines)
     The following properties:
         [set PI]
     are missing from row:
         Math= { get E: Number
               , get LN10: Number
               , get LN2: Number

Taming 'this'

Rather than sweeping this under the rug, it's represented in the type system appropriately.


Example 1:
function setX(x) { this.x = x; }
({ bla : setX, x : 0 }).bla(2); // OK! called with a valid 'this'
Infernu output:
setX :  { x: a | b}.(a -> Undefined)

Example 2:
function setX(x) { this.x = x; }
setX(2); // oops! setX will get 'undefined' for 'this'.
Infernu output:
:2:6: Error: 
(...many more lines)
     Failed unifying:
          { x: a | b}
     With:
         EmptyThis

Safe Overloading with Type Classes

a + b: are they strings? numbers? Infernu handles such cases safely, without losing information.


Example:
function add(x,y) { return x + y; }
var a = add(1,2); var b = add('hello ', 'world');
Infernu output:
add : [Plus b] => a.((b,b) -> b)
a : Number
b : String

Safe Indexing

In foo[x]: What is foo - an array? A string? A map? Is x a number or a string? Infernu safely represents bracket syntax get/set.


Example 1:
function getAt(obj, ix) { return obj[ix]; }
var a = getAt([1,2], 0);
var b = getAt('hi', 2);
Infernu output:
getAt : a.(( { get =[]: Rdv.(b -> c) | d},b) -> c)
a : Number
b : String

Example 2:
var x = 'foo';
x[0] = 't'; // oops... can't set string indexes!
Infernu output:
*:2:1: Error: 
(...many more lines)
     The following properties:
         [get []=]
     are missing from row:
         String= { get charAt: String.(Number -> String)
                         , get charCodeAt: String.(Number -> Number)
                         , get concat: String.(String -> String)

Explicit Mutability

Arrays and objects are always mutable. What about variables? Infernu assumes that modification means you want a variable to be mutable. It gives an explicit Mut a type to any variable that is modified after the initial declaration.


Example:
var x = 0, y = 0;
x = 1; // x is mutable, y is not - and the type signature now reminds us.
Infernu output:
x : Mut Number
y : Number

More Info

Source code on github. Infernu is an open source project.

Older design docs:

dicussion

type-system


Copyright 2015 - Noam Lewis.

The examples on this page are generated by running Infernu during build, using Hakyll.