summaryrefslogtreecommitdiffhomepage
path: root/assemblyscript.html.markdown
blob: 1e258ea4172aeb89893e18dc89bcaa7fd73ad216 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
---
language: AssemblyScript
contributors:
    - ["Philippe Vlérick", "https://github.com/pvlerick"]
    - ["Steve Huguenin-Elie", "https://github.com/StEvUgnIn"]
    - ["Sebastian Speitel", "https://github.com/SebastianSpeitel"]
    - ["Max Graey", "https://github.com/MaxGraey"]
filename: learnassemblyscript.ts
---

__AssemblyScript__ compiles a variant of __TypeScript__ (basically JavaScript with types) to __WebAssembly__ using __Binaryen__. It generates lean and mean WebAssembly modules while being just an `npm install` away.

This article will focus only on AssemblyScript extra syntax, as opposed to [TypeScript](/docs/typescript) and [JavaScript](/docs/javascript).

To test AssemblyScript's compiler, head to the
[Playground](https://www.assemblyscript.org/editor.html#IyFydW50aW1lPXN0dWIKLyoqIENhbGN1bGF0ZXMgdGhlIG4tdGggRmlib25hY2NpIG51bWJlci4gKi8KZXhwb3J0IGZ1bmN0aW9uIGZpYihuOiBpMzIpOiBpMzIgewogIHZhciBhID0gMCwgYiA9IDEKICBpZiAobiA+IDApIHsKICAgIHdoaWxlICgtLW4pIHsKICAgICAgbGV0IHQgPSBhICsgYgogICAgICBhID0gYgogICAgICBiID0gdAogICAgfQogICAgcmV0dXJuIGIKICB9CiAgcmV0dXJuIGEKfQoKIyFodG1sCjx0ZXh0YXJlYSBpZD0ib3V0cHV0IiBzdHlsZT0iaGVpZ2h0OiAxMDAlOyB3aWR0aDogMTAwJSIgcmVhZG9ubHk+PC90ZXh0YXJlYT4KPHNjcmlwdD4KbG9hZGVyLmluc3RhbnRpYXRlKG1vZHVsZV93YXNtLCB7IC8qIGltcG9ydHMgKi8gfSkKICAudGhlbigoeyBleHBvcnRzIH0pID0+IHsKICAgIGNvbnN0IG91dHB1dCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdvdXRwdXQnKQogICAgZm9yIChsZXQgaSA9IDA7IGkgPD0gMTA7ICsraSkgewogICAgICBvdXRwdXQudmFsdWUgKz0gYGZpYigke2l9KSA9ICR7ZXhwb3J0cy5maWIoaSl9XG5gCiAgICB9CiAgfSkKPC9zY3JpcHQ+Cg==) where you will be able
to type code, have auto completion and directly see the emitted WebAssembly.

```ts
// There are many basic types in AssemblyScript,
let isDone: boolean = false;
let name: string = "Anders";

// but integer type come as signed (sized from 8 to 64 bits)
let lines8: i8 = 42;
let lines16: i16 = 42;
let lines32: i32 = 42;
let lines64: i64 = 42;

// and unsigned (sized from 8 to 64 bits),
let ulines8: u8 = 42;
let ulines16: u16 = 42;
let ulines32: u32 = 42;
let ulines64: u64 = 42;

// and float has two sizes possible (32/64).
let rate32: f32 = 1.0
let rate64: f64 = 1.0

// But you can omit the type annotation if the variables are derived
// from explicit literals
let _isDone = false;
let _lines = 42;
let _name = "Anders";

// Use const keyword for constants
const numLivesForCat = 9;
numLivesForCat = 1; // Error

// For collections, there are typed arrays and generic arrays
let list1: i8[] = [1, 2, 3];
// Alternatively, using the generic array type
let list2: Array<i8> = [1, 2, 3];

// For enumerations:
enum Color { Red, Green, Blue };
let c: Color = Color.Green;

// Functions imported from JavaScript need to be declared as external
// @ts-ignore decorator
@external("alert")
declare function alert(message: string): void;

// and you can also import JS functions in a namespace
declare namespace window {
  // @ts-ignore decorator
  @external("window", "alert")
  function alert(message: string): void;
}

// Lastly, "void" is used in the special case of a function returning nothing
export function bigHorribleAlert(): void {
  alert("I'm a little annoying box!"); // calling JS function here
}

// Functions are first class citizens, support the lambda "fat arrow" syntax

// The following are equivalent, the compiler does not offer any type
// inference for functions yet, and same WebAssembly will be emitted.
export function f1 (i: i32): i32 { return i * i; }
// "Fat arrow" syntax
let f2 = (i: i32): i32 => { return i * i; }
// "Fat arrow" syntax, braceless means no return keyword needed
let f3 = (i: i32): i32 => i * i;

// Classes - members are public by default
export class Point {
  // Properties
  x: f64;

  // Constructor - the public/private keywords in this context will generate
  // the boiler plate code for the property and the initialization in the
  // constructor.
  // In this example, "y" will be defined just like "x" is, but with less code
  // Default values are also supported

  constructor(x: f64, public y: f64 = 0) {
    this.x = x;
  }

  // Functions
  dist(): f64 { return Math.sqrt(this.x * this.x + this.y * this.y); }

  // Static members
  static origin: Point = new Point(0, 0);
}

// Classes can be explicitly marked as extending a parent class.
// Any missing properties will then cause an error at compile-time.
export class PointPerson extends Point {
  constructor(x: f64, y: f64, public name: string) {
    super(x, y);
  }
  move(): void {}
}

let p1 = new Point(10, 20);
let p2 = new Point(25); //y will be 0

// Inheritance
export class Point3D extends Point {
  constructor(x: f64, y: f64, public z: f64 = 0) {
    super(x, y); // Explicit call to the super class constructor is mandatory
  }

  // Overwrite
  dist(): f64 {
    let d = super.dist();
    return Math.sqrt(d * d + this.z * this.z);
  }
}

// Namespaces, "." can be used as separator for sub namespaces
export namespace Geometry {
  class Square {
    constructor(public sideLength: f64 = 0) {
    }
    area(): f64 {
      return Math.pow(this.sideLength, 2);
    }
  }
}

let s1 = new Geometry.Square(5);

// Generics
// AssemblyScript compiles generics to one concrete method or function per set
// of unique contextual type arguments, also known as [monomorphisation].
// Implications are that a module only includes and exports concrete functions
// for sets of type arguments actually used and that concrete functions can be
// shortcutted with [static type checks] at compile time, which turned out to
// be quite useful.
// Classes
export class Tuple<T1, T2> {
  constructor(public item1: T1, public item2: T2) {
  }
}

export class Pair<T> {
  item1: T;
  item2: T;
}

// And functions
export function pairToTuple <T>(p: Pair<T>): Tuple<T, T> {
  return new Tuple(p.item1, p.item2);
};

let tuple = pairToTuple<string>({ item1: "hello", item2: "world" });

// Including references to a TypeScript-only definition file:
/// <reference path="jquery.d.ts" />

// Template Strings (strings that use backticks)
// String Interpolation with Template Strings
let name = 'Tyrone';
let greeting = `Hi ${name}, how are you?`
// Multiline Strings with Template Strings
let multiline = `This is an example
of a multiline string`;

let numbers: Array<i8> = [0, 1, 2, 3, 4];
let moreNumbers: Array<i8> = numbers;
moreNumbers[5] = 5; // Error, elements are read-only
moreNumbers.push(5); // Error, no push method (because it mutates array)
moreNumbers.length = 3; // Error, length is read-only
numbers = moreNumbers; // Error, mutating methods are missing

// Type inference in Arrays
let ints = [0, 1, 2, 3, 4]  // will infer as Array<i32>
let floats: f32[] = [0, 1, 2, 3, 4]  // will infer as Array<f32>
let doubles = [0.0, 1.0, 2, 3, 4]  // will infer as Array<f64>
let bytes1 = [0 as u8, 1, 2, 3, 4]  // will infer as Array<u8>
let bytes2 = [0, 1, 2, 3, 4]  as u8[] // will infer as Array<u8>
let bytes3: u8[] = [0, 1, 2, 3, 4] // will infer as Array<u8>
```

## Further Reading

 * [AssemblyScript Official website](https://www.assemblyscript.org/)
 * [AssemblyScript source documentation](https://github.com/AssemblyScript/website/tree/main/src)
 * [Source Code on GitHub](https://github.com/AssemblyScript/assemblyscript)