Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Facebook's invariant vs if throw

I've been looking at various Node.js projects' source, and I've noticed that some people use invariant. From what I understood, invariant is a tool that lets you put assertions in your code, and raise errors as needed.

Question:

When would you favor using invariant vs throwing errors the traditional way?

// Using invariant
function doSomething(a, b) {
   invariant(a > b, 'A should be greater than B');
}

// If throw
function doSomething(a, b) {
   if(a <= b) {
      throw new Error('A should be greater than B');
   }
}
like image 608
rodrigo-silveira Avatar asked Aug 20 '16 14:08

rodrigo-silveira


2 Answers

There are a few reasons:

  • It's easier to read when you want to stack them. If you have, say, 3 preconditions to validate, you always see invariant(x ..., and it's easy to see what's being checked:

function f(xs, x) {
    // all the invariants are lined up, one after another
    invariant(xs.type == x.type, "adding an element with the same type");
    invariant(xs.length != LIST_MAX_SIZE, "the list isn't full");
    invariant(fitting(x), "x is fitting right in the list");
}

Compare with the usual throw approach:

function f(xs, x) {
    if (xs.type != x.type)
       throw new Error("adding an element with the same type");
    if (xs.length == LIST_MAX_SIZE)
       throw new Error("the list isn't full");
    if (!fitting(x))
       throw new Error("x is fitting right in the list");
}

  • It makes it easy to eliminate it in release build.

    It's often that you want preconditions checked in dev/test, but don't want them in release because of how slow they'd be. If you have such an invariant function, you can use a tool like babel (or some other) to remove these calls from production builds (this is somewhat like how D does it).

like image 86
Ven Avatar answered Nov 14 '22 10:11

Ven


zertosh/invariant allows to add code guards

As said in the readme it is A way to provide descriptive errors in development but generic errors in production.

however it is a replication of some internal facebook's systems and imo is pretty bad documented and not maintained. Scary thing is the 4.4M uses :thinking:

  • nothing will be striped out of the box
  • if you don't have a build tool that somehow remove your message in production you will still have the original error
  • the usage in node is for ssr/react native, or useless outside of the "we have less lines" thing
  • it uses error.framesToPop which also is a facebook thing

see: https://github.com/zertosh/invariant/issues?q=is%3Aissue

Note: A better aproach will be to wait for the es proposal throw inline and actually do

cond || throw x
cond ?? throw x

that way the error will not be evaluated anyway and stripped if cond includes a falsy var env in the browser

like image 5
Sceat Avatar answered Nov 14 '22 09:11

Sceat