-
Notifications
You must be signed in to change notification settings - Fork 48
Using null conditional operators
Null-conditional operators are syntactic sugar that allows easier access to potentially-amiss values.
So, for example, if you wanted to grab the nearest enemy's health or 0 if there isn't such an enemy, you would usually do something like
var nearest_enemy = instance_nearest(x, y, obj_enemy);
var nearest_enemy_health = nearest_enemy != noone ? nearest_enemy.cur_health : 0;
but with this you could do
var nearest_enemy_health = instance_nearest(x, y, obj_enemy)?.cur_health ?? 0;
With support for expressions, variable access, array access, and all the various GameMaker accessors, this can spare you a lot of typing at a minor cost.
Operator | Syntax | Equivalent to |
---|---|---|
?? |
a ?? b |
a != undefined ? a : b |
?. |
a?.field |
(a != undefined ? a.field : undefined) |
?[ |
a?[index] |
(a != undefined ? a[index] : undefined) |
?[| |
list?[|index] |
(list != undefined ? list[|index] : undefined) |
?[? |
map?[?key] |
(map != undefined ? map[?key] : undefined) |
?[# |
grid?[#x, y] |
(grid != undefined ? grid[#x, y] : undefined) |
?[$ |
struct?[$ field] |
(struct != undefined ? struct[$ field] : undefined) |
Since the left-hand expression may have arbitrary complexity and/or side effects, GMEdit uses a little trick - fn() ?? def
will be compiled to nc_set(fn()) ? nc_val : def
, where nc_set
assigns nc_val
and returns whether the argument is "valid".
So, you would start with making a script with a globalvar (or a macro if you are feeling pedantic) inside.
For GMS2.3, it could look like so:
globalvar nc_val; nc_val = undefined;
/// @param value
/// @returns {bool} Whether the value is non-null
function nc_set(v) {
nc_val = v;
return v != undefined && v != noone;
}
For older versions, the script would look as following:
/// nc_set(value)->bool
globalvar nc_val;
gml_pragma("global", "nc_val = undefined;");
nc_val = argument0;
return argument0 != undefined && argument0 != noone;
Then you would open your Project Properties (from menu or Ctrl+Shift+T), enter your script and variable names (nc_set
and nc_val
in this example) under "Syntax Extensions ➜ Null-conditional operators", and that's all! You can now use the syntax and check the transformed code in your saved file.
- Although
?.
and?[
check that the context is notundefined
, they do not check for whether a variable exists / whether the index is in-bounds, so you can still run into errors that way.
For structs/instances, you can get around this by using the 2.3.1?[$key]
accessor.
Arrays can be replaced with lists depending on use case. - Since
??
does very literally convert into a ternary operator, you should be mindful of operator priority - soa + b ?? c + d
would convert toa + b != undefined ? b : c + d
(countinga
towards condition), buta + (b ?? c) + d
will be fine. - GameMaker does not allow ternary operator chaining so
a ?? b ?? c
will not compile buta ?? (b ?? c)
or(a ?? b) ?? c
are fine.
- Smart auto-completion
- Types
- JSDoc tags (incl. additional ones)
- @hint tag (mostly 2.3)
- `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)