Skip to content
Vadim Dyachenko edited this page Dec 6, 2021 · 10 revisions

Complementary to #import magic, type magic allows to further improve the readability and shorten the code. It is also used for smart completion and error checking.

First, when you declare a local variable, you can specify its type after a name:

var v:Type;

// or:
var v:Type = value;

// or with #args magic:
#args v:Type, ?z:Type, q:Type = value

// or with function arguments and/or return types in GMS≥2.3:
function name(v:Type, z:Type, q:Type)->Type {
    // (z is undefined by default if not provided)
    q ??= value;
    // ...
}

if the "type" is an #import namespace, you will be able to use any functions from the namespace as variable's "methods":

#import string.* as String
var s:String = "hi";
return s.repeat(2); // -> string_repeat(s, 2) -> "hihi"

if the namespace has a function called "create", you can also use a keyword "new" on the namespace, and it'll translate to that:

#import ds_grid.* as Grid
return new Grid(4, 4); // -> ds_grid_create(4, 4)

Note that type magic only works with local variables. Use @hint or @is to specify types for global/instance variables.


If you specify an enum as a type instead, you can do .field access with constant names from enum as if it was a lightweight object:

enum Vec2 { x, y, sizeof }
var v:Vec2 = argument0;
v.x = 1; // -> v[@Vec2.x]
return v.y; // -> v[Vec2.y]

if your enum ends with a separate constant to mark the number of other constants inside of it, you can use Type() to construct an empty copy of it:

enum Vec2 { x, y, sizeof }
var v:Vec2 = Vec2(); // -> array_create(Vec2.sizeof);

and you can import scripts/functions on top of them:

enum Vec2 { x, y, sizeof }
#import vec2.* in Vec2 // where you have vec2_create(x, y), vec2_add(v, x, y)
var v:Vec2 = new Vec2(2, 3); // -> vec2_create(2, 3)
return v.add(new Vec2(4, 5)); // -> vec2_add(v, vec2_create(4, 5))

Since January 2019 update, you can also use #import com.pkg.some in NS:name syntax to be able to do

#import buffer_* in Buffer:
#import buffer_create in Buffer.create
#import buffer_get_address in Buffer:ptr
var b:Buffer = new Buffer(64, buffer_grow, 1);
some_func(b.ptr(), b.tell());

without turning every non-type-magic buffer_tell(buf) into Buffer.tell(buf)

Better workflow:

Syntax extensions:

  • `vals: $v1 $v2` (template strings)
  • #args (pre-2.3 named arguments)
  • ??= (for pre-GM2022 optional arguments)
  • ?? ?. ?[ (pre-GM2022 null-conditional operators)
  • #lambda (pre-2.3 function literals)
  • => (2.3+ function shorthands)
  • #import (namespaces and aliases)
  • v:Type (local variable types)
  • #mfunc (macros with arguments)
  • #gmcr (coroutines)

Customization:

User-created:

Other:

Clone this wiki locally