JavaScript
Article

Spider: An Exciting Alternative to JavaScript

By Florian Rappl

Spider is one of the new languages that try to improve our codes by providing more reliability. Some could certainly describe it as CoffeeScript with JavaScript syntax, but such description would fail to emphasize the real benefits of Spider.

Spider contains a lot more unique and interesting concepts than most alternatives like CoffeeScript. While the latter is certainly more mature than Spider, we get some nice options by choosing the language named after the eight legged arthropods. If we just want to experiment a little bit with yet another language, search for a trustworthy JavaScript alternative, or try to write less and do more, Spider seems to be a good candidate.

Basic Concepts

Spider is designed around its slogan, It’s just JavaScript, but better. This means we won’t get a compilation type system or type checker of any kind. We also won’t miss our beloved C-style syntax with curly brackets for blocks, round brackets for function calls, and square brackets for arrays. Finally we also don’t see a custom VM on top of JavaScript or anything else to break compatibility with existing JavaScript code. Yes, this is really JavaScript.

The creators of Spider realized that there is no point in debating static versus dynamic languages. Each one has their advantages and disadvantages. The reason for choosing the full dynamic side with Spider is simple: JavaScript is already dynamic and interacting with otherwise dynamic code gets a lot simpler when the language embraces a dynamic type system.

There are two more important things that should be mentioned here:

  1. Spider is compiled to JavaScript (i.e. transpiled)
  2. Some features are inspired from languages like Go, C#, and CoffeeScript

The files are not transpiled to older versions of JavaScript, but to the most recent standard ECMAScript 6. To guarantee support across most browsers, Spider uses Google’s Traceur to generate ECMAScript 5 compatible files. What this means is that Spider is already taking advantage of future improvements, with the current output being backward compatible.

Syntax

Spider includes the :: operator to access the global scope. This prevents us from doing something stupid without realizing it. However, this also means we need to write a little bit more to access, for instance, the console object. The statement below shows an example that uses the :: operator:

::console.log("Hello world!");

A possible way around this is to use the use statement. It allows us to reference a locally undeclared symbol.

use console;

console.log("Hello world!");

Spider provides certain macros that unlock some well-known global objects. Depending on the type of application you’re developing, these macros can be more or less useful. One example is the following:

use :browser;

console.log(document.title, window.screen);

The :browser macro allows us to use objects such as document, console, window, location, and many more directly. A very helpful feature for DOM intensive applications.

Instead of keeping all the former logical operators, some have been replaced. For instance the equality and inequality operators (== and !=) play now the role of strict equality and strict inequality (=== and !== in JavaScript). The “and” (&&) and the “or” (||) operators also transform the value and have been renamed to and and or respectively. Here is an example:

// x == true;
x = false or 5;

// x == true;
x = 5 and 4;

// x == false;
x = 1 == "1";

Now some of you will scream, stop reading this article, and also close the page. But wait… don’t leave so fast!

The logical-and and logical-or operators have also been abused for controlling flow and placing default values. While the former is not so interesting, the latter can be a real time saver. The language uses the null-coalescing operator ?? from C# to cover default values:

x = options.name ?? 'default name';

At this point we are ready to have a look at functions. Functions are what make JavaScript so interesting. Spider doesn’t take away anything, except a few characters:

var square = fn (x) {
  return x * x;
};

Instead of writing function, in Spider we can write fn. This saves us from typing a few keystrokes while keeping the same structure. As in JavaScript we can use functions in function statements or in function expressions. Function statements are restricted to named functions, just like in JavaScript.

Additionally we can use the function arrow -> as in Java lambda expressions (and similar to the arrow functions in JavaScript). The previous example could be expressed as follows:

var square = (x) -> x * x;

If you don’t write a block, the function will immediately return the provided expression. On the contrary, if you have a block of statements you need to use a return statement for returning a value.

But the simple function arrow is not enough. As in the TypeScript language (and also in ECMAScript 6) we also have the fat arrow => operator. This one is a context preserving function arrow. If you want to learn more about the arrow functions in JavaScript, I suggest you to read the article Preparing for ECMAScript 6: New Function Syntax.

The following is an example of this operator in Spider:

fn Animal(name) {
  this.name = name;

  this.printNameLater = () => {
    ::setTimeout(() => {
      ::console.log(this.name);
    }, 1000);
  };
}

One additional remark for functions is the ability to specify default parameters and use the rest parameters like in ECMAScript 6. The former automatically generates code to check and fix missing (i.e. undefined) arguments. The latter is similar to variable argument lists. It basically groups all additional, unnamed parameters into one named array:

fn format(text, parameters...) {
	for parameter, index in parameters
		text = text.replace('{' + index + '}', parameter);
	return text;
}

format("Hi {0}! My name is {1}.", "World", "Florian");

In the previous example we’ve also seen one of Spider’s elegant ways to write a loop. We used a classic foreach loop with an additional iteration counter. Spider also contains more such features, as we will see in the next section.

Features

Spider brings a lot more safety to JavaScript by introducing more consistency. An example for a more consistent approach can be found in the name of types.

// "object"
typeof { a: 4 };
// "array"
typeof [1, 2, 3];
// "date"
typeof new Date;
// "number"
typeof new Number(4);
// "string"
typeof new String("abc");
// "boolean"
typeof new Boolean(true);

As you can see the type for arrays and dates is different from JavaScript and it’s more close to what you (or most people) would expect. Another safety check can be found with the existential operator ?. It transforms any expression to a check for null or undefined. This can be quite handy:

if game? {
  play();
}

There are also other variants, namely ?. (also called Elvis operator) for calling properties or ?() for calling functions. Hence the following could make sense:

game?.play?();

Here we only access the play property if game is defined. If play is not a function, then nothing is called.

Transpilation

I’ve already mentioned that Spider actually transpiles to ECMAScript 6. As a positive side effect, Spider is quite future proof and uses features of JavaScript that are accessible today. However, there is also a disadvantage in targeting ES6: we still need another transpiler to convert the output to ES5 or lower, which can be interpreted by all modern browsers (including older versions of Internet Explorer).

For the transpilation we need the Spider compiler. The best solution is to install the npm package spider-script:

npm install -g spider-script

This also installs Traceur, PEG.js and a bunch of other dependencies. The major drawback of using Traceur is an additional runtime dependency.

At this point we have access to the Spider compiler, which is called spider. By default the compiler transpiles and runs the code in ES5 mode without hitting the disk. However, there are several options to change that behavior and write output files with optional source maps instead.

A Short Demo

Rather than staying on the theoretical side, I want you to practice a bit with Spider by creating a small demo application. Our goal is to use as many of the features of Spider as possible. Apart from that, the demo should also be fun to use, so we’ll create a simple game. By creating this project, you’ll also have a glance at Spider’s amazing inheritance features.

The Basic Concept

We’ll create a simple space shooter game where our ship is portrayed as a triangle and opponents are represented as circles. Any collision will result in an annihilation of the player. The game will be drawn by using an HTML5 canvas with a 2D drawing context.

We won’t focus on the graphics, as our attention and interested should be focused on the code. We’ll create a constructor function called GameObject(), which will also be the prototype of the constructor functions PlayerShip() and Asteroid(). An object game will aggregate all the objects of the game.

To start you’ll need to download a few resources for our game. We require a nice background image and a sound to play in case of a collision. The game is controlled via the arrow keys of the keyboard.

Implementation in Spider

Every game requires a sort of resource loader. The demand is even higher if resources are loaded via a network. The following method encapsulates the process of loading an image from a given URL in a promise:

fn loadImage(url) {
	return new Promise(fn (fulfill, reject) {
		var img = document.createElement('img');
		img.src = url;
		img.onload = () -> {
			fulfill(img);
		};
		img.onerror = () -> {
			reject(img);
		};
	});
}

The interesting part is that we can simply use it in our startup routine, just as if we would deal with classic sequential code:

background.image = await loadImage('http://i.ytimg.com/vi/qbzFSfWwp-w/maxresdefault.jpg');

The background object is a special kind of dummy game object. The constructor function uses a GameObject as its prototype:

fn Background(game)
	extends GameObject(game) {
	this.draw = () => {
		if this.image? {
			var ctx = this.game.ctx;
			var img = this.image;
			var w = ctx.canvas.width;
			var h = ctx.canvas.height;
			ctx.drawImage(img, 0, 0, img.naturalWidth, img.naturalHeight, -0.5 * w, -0.5 * h, w, h);
		}
	};
}

We do not need to specify the prototype directly. We have to express our basic intent, which is to extend the GameObject constructor function with a more specialized one.

The game also contains other pseudo objects. As an example we might have a generator for asteroids. Here features such as inline loops and ranges come in handy. We only want to create an asteroid at a random time and a random position.

Getting three random numbers (here called a, b and c) can be done in a single line:

fn AsteroidGenerator(game) 
	extends GameObject(game) {
	this.move = () => {
		if Math.random() > 0.95 {
			var [a, b, c] = [Math.random() for i in [1..3]];
			// ...
			game.items <- new Asteroid(game, location, velocity, radius);
		}
	};
}

Finally, we also will employ helpers such as a simple Point constructor. As an example, we can always set a default value for any argument. This will reduce boilerplate code that only checks for undefined and applies the default value:

fn Point(x = 0, y = 0) {
	this.x = x;
	this.y = y;
	// ...
	this.dist = (that) => {
		return Math.sqrt(Math.pow(this.x - that.x, 2) + Math.pow(this.y - that.y, 2));
	};
}

The finished demo application can be viewed at html5.florian-rappl.de/Spider/. The original source code is accessible via GitHub.

Key Observations

Let’s recap the features we’ve seen in action:

  • async and await solve the callback hell
  • Prototype inheritance got simpler
  • Shorthand method names make the code more elegant
  • Ranges are great in many scenarios
  • Default values are helpful
  • The overall code is easier to read

In my opinion, reading Spider code does not feel strange or completely new to you. In fact, it turns out that this seems more like a natural extension to JavaScript than a new language.

Conclusion

Spider comes along with some handy new features and also brings some consistency to the table. It embraces the dynamic nature of JavaScript instead of fighting it. While other languages try to counter bugs by introducing compile-time features, Spider builds upon an improved language specification. A lot of bugs will definitely be gone for good.

In this article we’ve seen some of the unique selling points of Spider. We’ve also build a very small sample application that makes use of Spider’s new features. A lot more is possible with Spider than what I covered in this article. For this reason, I recommend you to check the official documentation available at spiderlang.org.

What’s your opinion on Spider? Does it have some appealing features or are you completely satisfied with your current workflow?

More:
  • WooDzu

    I don’t see a point in starting a JS project using a custom syntax. If the project grows to huge size within a year so that you need one or two new devs, it becomes a pain for them to get on with it. That is assuming, the syntax survives that long and documentation exists and it’s being maintained.

    • http://www.joezimjs.com Joe Zimmerman

      Personally I just think that if you’re going to make a compile-to-javascript language that uses a largely similar syntax to JS, just try to enhance TypeScript more by adding cool features… I guess they may have tried it, or they didn’t like what TS has done and wouldn’t want to mix, but honestly we don’t need more languages whose sole purpose is to be converted to JS.

      • WooDzu

        Completely agree. These times are so much overloaded with “features” already and new frameworks and libraries aren’t any exciting any more. Please do not try to convince me that new stuff is cool because it’s new and provides 10 new features to stack which had already had 1001.
        And the other hand side, reading only about JavaScript and PHP would be extremely boring, so thanks for the write up!

      • Florian Rappl

        Well, I think there are too many features that are orthogonal to TS. Additionally I guess the author of Spider didn’t like the mindset of TS. TS is great and I use it a lot, but there are many JS purists, who think that providing any kinds of compile-time mechanisms (such as type checking) is a step backwards.
        Maybe in a not to distant future, TS will open its compiler and allow extensions to be integrated during compile-time. That would enable a lot of cool meta-programming features.

  • David Zamora

    I didn’t think about it but a friend asked me, what about debugging? It may be pretty messy with this code to know in which part of the code you are having troubles or to indentify it.

    • WooDzu

      The article states “write output files with optional source maps” which would suggest that it’s possible to debug spider files from within browser’s dev tools.

    • Florian Rappl

      Yes @WooDzu:disqus is correct. Like most JS transpilers the Spider compiler will also produce a source map file, which is a standardized way for most web browsers to map JavaScript code to an arbitrary source. This way you can actually debug your original source file, even though the browser only knows how to handle the output of your transpilation process.

  • gapipro

    Pointless project if you don’t have your own interpreter embedded in browser. If it is compiled to JS then it is JS nothing more, and it can’t be in any case better then JS.

    • Florian Rappl

      If that’s true then writing C or any higher level language is also pointless. It can’t be better than assembly.

      • gapipro

        It’s pointless from performance standing. You can’t beat pure JS.

        • Florian Rappl

          While this is true if we fix the version of JS, it is not true in general. In a higher level language you can have constructs that may (over time) be implemented / supported in the lower level language. Without changing the code of the higher level language you can then benefit from the new features just by recompiling.

          Needless to say that Spider isn’t about performance. It’s about convenience.

  • Waleed Alabbady

    Why in hell should I Abandon the GREAT JAVASCRIPT and use some new insect !

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in JavaScript, once a week, for free.