-
Notifications
You must be signed in to change notification settings - Fork 47
Using #lambda magic
GMS≥2.3 note: This GMEdit feature has been superseded by native function literal support.
While older versions of GameMaker lack ability to easily organize inline and related scripts, that is a fixable oversight.
The premise is simple enough - when you save a file, GMEdit puts your #lambda
scripts into an extension. When you open the file, GMEdit extracts them from the extension for ease of editing. Let's suppose you have the following:
#event create
on_click = #lambda { trace("hello!") };
#event mouse_left_press
script_execute(on_click);
If you were then to inspect your event in GMS, it might look like so:
on_click = __lf_obj_test_create_;
while the extension's GML file would have the actual script and a bit of metadata for displaying it as authored:
#define __lf_obj_test_create_
//!#lambda$
{ trace("hello!") }
-
Add a new extension called
gmedit_lambda
(right-click Extensions section in resource tree)
-
Add a placeholder GML file to it
The shortest syntax for lambdas is just like so:
#lambda { ...code }
you can assign it to a variable,
on_click = #lambda { show_debug_message("hi!"); }
or use it as a function argument,
scr_wait(#lambda {
show_debug_message("hi!");
}, room_speed * 3);
or even call it immediately if you really just wanted something that you could return
from,
var target = #lambda {
with (obj_player) {
if (collision_line(x, y, other.x, other.y, obj_wall, false, false) == noone) return self;
}
return noone;
} ();
While you can use argument
or #args magic as usual inside inline functions, you may instead include arguments on the declaration line for even lower redundancy:
#lambda (...args) { ...code }
So, for instance, if you have a script that brings up a custom input prompt and later calls the specified script with the result, you could have it like so:
scr_prompt(#lambda (name) {
scr_say("Hi, " + name + "!");
}, "What's your name?", "a person");
Various #args
features (optional, default values) are also supported.
You can name your inline functions, like so:
#lambda name { ...code }
#lambda name(...args) { ...code }
This does 2 things for you:
- Uses name as suffix in auto-generated scripts (for ease of debugging)
- Allows to reference/call the function by defined name in the same script/event
var fn = #lambda some {
show_debug_message("hi!");
};
script_execute(fn); // works
script_execute(some); // also works
some(); // shorter!
on_click = #lambda rec(i) {
if (i > 0) rec(i - 1);
show_debug_message(i);
};
If you do not want to assign the resulting function anywhere, you can do so by replacing #lambda
with #lamdef
in any syntax version,
/// scr_some(...)
#lamdef debug(v) {
show_debug_message("scr_some: " + string(v));
}
/// ...
debug("OK!");
-
Variable/local scope capture is not supported; it is not known what implementation GML itself is going to use.
In less technical terms, an inline function is still just a script, and will not be able to use surrounding script's local variables unless you feed them to it as an argument.
-
GMEdit does not differentiate between in-lambda/out-of-lambda local variables - they are all highlighted as per containing script/event/moment. This will not change for a while as the choice was between this and having lambdas defined at the end of a file (which is admittedly less fancy). If you feel like you could rewrite scope detection to mind closure nesting while retaining the required performance, you can check out
gml.GmlScopes
.
- 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)