# Peculiarities

Special features that exist for the sole reason of why not.

# Annotations

Decorators work more like actual compiler annotations in AssemblyScript.

Annotation Description
@inline Requests inlining of a constant or function.
@lazy Requests lazy compilation of a variable. Useful to avoid unnecessary globals.
@global Registers an element to be part of the global scope.
@external Changes the external name of an imported element. @external(module, name) changes both the module and element name, @external(name) changes the element name only.
@operator Annotates a method as a binary operator overload. See below.
@operator.binary Alias of @operator.
@operator.prefix Annotates a method as a unary prefix operator overload. See below.
@operator.postfix Annotates a method as a unary postfix operator overload. See below.

Custom decorators can be given meaning by using a transform.

# Operator overloads

Operator overloads can only be used on class methods. The respective argument types must match the class type.

# Binary operations

@operator(OP)
static __op(left: T, right :T): T { ... }

@operator(OP)
__op(right: T): T  { ... }
OP Description
"[]" Checked indexed get
"[]=" Checked indexed set
"{}" Unchecked indexed get
"{}=" Unchecked indexed set
"==" Equality
"!=" Inequality
">" Greater than
">=" Greater than or equal
"<" Less than
"<=" Less than or equal
">>" Arithmetic right shift
">>>" Logical right shift
"<<" Left shift
"&" Bitwise AND
"|" Bitwise OR
"^" Bitwise XOR
"+" Addition
"-" Subtraction
"*" Multiplication
"/" Division
"**" Exponentiation
"%" Remainder

The === operation cannot be overloaded (is identity equality).

# Unary prefix operations

@operator.prefix(OP)
static __op(self: T): T { ... }

@operator.prefix(OP)
__op(): T { ... }
OP Description Notes
"!" Logical NOT
"~" Bitwise NOT
"+" Unary plus
"-" Unary negation
"++" Prefix increment Instance overload reassigns
"--" Prefix decrement Instance overload reassigns

TIP

Note that increment and decrement overloads can have slightly different semantics. If the overload is declared as an instance method, on ++a the compiler does emit code that reassigns the resulting value to a while if the overload is declared static, the overload behaves like any other overload, skipping the otherwise implicit assignment.

# Unary postfix operations

@operator.postfix(OP)
static __op(self: T): T { ... }

@operator.postfix(OP)
__op(): T { ... }
OP Description Notes
"++" Postfix increment Instance overload reassigns
"--" Postfix decrement Instance overload reassigns

TIP

Overloaded postfix operations do not preserve the original value automatically.

# Range limits

The following range limits are present as global constants for convenience:

  • const i8.MIN_VALUE: i8 = -128
    const i8.MAX_VALUE: i8 = 127
    
  • const i16.MIN_VALUE: i16 = -32768
    const i16.MAX_VALUE: i16 = 32767
    
  • const i32.MIN_VALUE: i32 = -2147483648
    const i32.MAX_VALUE: i32 = 2147483647
    
  • const i64.MIN_VALUE: i64 = -9223372036854775808
    const i64.MAX_VALUE: i64 = 9223372036854775807
    
  • const isize.MIN_VALUE: isize // WASM32: i32.MIN_VALUE, WASM64: i64.MIN_VALUE
    const isize.MAX_VALUE: isize // WASM32: i32.MAX_VALUE, WASM64: i64.MAX_VALUE
    
  • const u8.MIN_VALUE: u8 = 0
    const u8.MAX_VALUE: u8 = 255
    
  • const u16.MIN_VALUE: u16 = 0
    const u16.MAX_VALUE: u16 = 65535
    
  • const u32.MIN_VALUE: u32 = 0
    const u32.MAX_VALUE: u32 = 4294967295
    
  • const u64.MIN_VALUE: u64 = 0
    const u64.MAX_VALUE: u64 = 18446744073709551615
    
  • const usize.MIN_VALUE: usize = 0
    const usize.MAX_VALUE: usize // WASM32: u32.MAX_VALUE, WASM64: u64.MAX_VALUE
    
  • const bool.MIN_VALUE: bool = 0
    const bool.MAX_VALUE: bool = 1
    
  • const f32.MIN_VALUE: f32 = -3.40282347e+38
    const f32.MAX_VALUE: f32 = 3.40282347e+38
    const f32.MIN_SAFE_INTEGER: f32 = -16777215
    const f32.MAX_SAFE_INTEGER: f32 = 16777215
    const f32.EPSILON: f32 = 1.19209290e-07
    
  • const f64.MIN_VALUE: f64 = -1.7976931348623157e+308
    const f64.MAX_VALUE: f64 = 1.7976931348623157e+308
    const f64.MIN_SAFE_INTEGER: f64 = -9007199254740991
    const f64.MAX_SAFE_INTEGER: f64 = 9007199254740991
    const f64.EPSILON: f64 = 2.2204460492503131e-16
    

# Tree-shaking

# Module-level

The compiler only compiles elements reachable from the entry file and ignores everything that remains unused. This is very similar to a JavaScript VM's behavior when running a JavaScript file, but unlike in TypeScript it also affects checking of types. Helps to reduce compilation times and binary sizes significantly.

# Branch-level

In addition to module-level tree-shaking, the compiler ignores branches that it can prove won't be taken. Works with constants, built-ins that compile to a constant, expressions that can be precomputed to a constant, plus the following globals to detect specific compiler flags or features:

  • const ASC_TARGET: i32
    

    Indicates the compilation target. Possible values are 0 = JS (portable), 1 = WASM32, 2 = WASM64.

  • const ASC_NO_ASSERT: bool
    

    Whether --noAssert has being set.

  • const ASC_MEMORY_BASE: usize
    

    The value of --memoryBase.

  • const ASC_OPTIMIZE_LEVEL: i32
    

    The value of --optimizeLevel. Possible values are 0, 1, 2 and 3.

  • const ASC_SHRINK_LEVEL: i32
    

    The value of --shrinkLevel. Possible values are 0, 1 and 2.

  • const ASC_FEATURE_SIGN_EXTENSION: bool
    const ASC_FEATURE_MUTABLE_GLOBALS: bool
    const ASC_FEATURE_NONTRAPPING_F2I: bool
    const ASC_FEATURE_BULK_MEMORY: bool
    const ASC_FEATURE_SIMD: bool
    const ASC_FEATURE_THREADS: bool
    const ASC_FEATURE_EXCEPTION_HANDLING: bool
    const ASC_FEATURE_TAIL_CALLS: bool
    const ASC_FEATURE_REFERENCE_TYPES: bool
    

    Whether the respective feature is enabled.

For example, if a library supports SIMD but also provides a fallback:

if (ASC_FEATURE_SIMD) {
  // compute with SIMD operations
} else {
  // fallback without SIMD operations
}