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:
- Spider is compiled to JavaScript (i.e. transpiled)
- Some features are inspired from languages like Go, C#, and CoffeeScript
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 calledGameObject()
, 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
andawait
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
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?Frequently Asked Questions about Spider, an Exciting Alternative to JavaScript
What makes Spider different from JavaScript?
Spider is a programming language that is designed to be a more efficient and user-friendly alternative to JavaScript. It incorporates features from other languages such as Python and Ruby, which makes it more versatile and easier to use. Unlike JavaScript, Spider supports multiple inheritance and operator overloading, which can make coding more efficient. It also has a cleaner syntax, which can make your code easier to read and maintain.
How can I start using Spider?
To start using Spider, you need to install it on your computer. You can download it from the official Spider website. Once installed, you can start writing Spider code in any text editor. To run your Spider code, you need to compile it into JavaScript using the Spider compiler.
Can I use Spider for web development?
Yes, you can use Spider for web development. Spider is designed to be a more efficient and user-friendly alternative to JavaScript, which is widely used in web development. You can use Spider to write client-side code for your web applications. After writing your Spider code, you can compile it into JavaScript using the Spider compiler.
What are the advantages of using Spider over JavaScript?
Spider has several advantages over JavaScript. It has a cleaner syntax, which can make your code easier to read and maintain. It supports multiple inheritance and operator overloading, which can make coding more efficient. It also incorporates features from other languages such as Python and Ruby, which makes it more versatile and easier to use.
Is Spider compatible with JavaScript libraries and frameworks?
Yes, Spider is compatible with JavaScript libraries and frameworks. After writing your Spider code, you can compile it into JavaScript using the Spider compiler. The compiled JavaScript code can then be used with any JavaScript library or framework.
How does Spider improve code readability?
Spider improves code readability by having a cleaner syntax compared to JavaScript. It eliminates unnecessary punctuation and uses indentation to denote code blocks, similar to Python. This makes the code easier to read and understand, which can help reduce errors and improve maintainability.
Can I use Spider for server-side programming?
Currently, Spider is primarily used for client-side programming. However, since it compiles into JavaScript, you can use it for server-side programming in environments that support JavaScript, such as Node.js.
Is Spider a statically typed or dynamically typed language?
Spider is a dynamically typed language, like JavaScript. This means that you don’t have to declare the data type of a variable when you create it. This can make coding faster and more flexible, but it can also lead to potential errors if you’re not careful.
How does Spider handle object-oriented programming?
Spider supports object-oriented programming and incorporates features from other object-oriented languages. It supports multiple inheritance, which allows a class to inherit characteristics from more than one superclass. It also supports operator overloading, which allows you to redefine how operators work with your custom objects.
Is there a large community of developers using Spider?
While Spider is not as widely used as JavaScript, it has a growing community of developers. There are online forums and resources where you can connect with other Spider developers, ask questions, and share your knowledge.
Florian Rappl is an independent IT consultant working in the areas of client / server programming, High Performance Computing and web development. He is an expert in C/C++, C# and JavaScript. Florian regularly gives talks at conferences or user groups. You can find his blog at florian-rappl.de.