diff --git a/docs/scarpet/Full.md b/docs/scarpet/Full.md index bd8c1ae3..0d731ea7 100644 --- a/docs/scarpet/Full.md +++ b/docs/scarpet/Full.md @@ -804,6 +804,9 @@ a = 3; task_thread('temp', _(outer(a), b) -> foo(a,b), 5) => Another example of running the same thing passing arguments using closure over anonymous function as well as passing a parameter. +In case you want to create a task based on a function that is not defined in your module, please read the tips on + "Passing function references to other modules of your application" section in the `call(...)` section. + ### `sleep()` `sleep(timeout)`, `sleep(timeout, close_expr)` @@ -1373,7 +1376,7 @@ foo(... x) -> ... # all arguments for foo are included in the list ### `import(module_name, symbols ...)` Imports symbols from other apps and libraries into the current one: global variables or functions, allowing to use -them in the current app. This include other symbols imported by these modules. Scarpet supports cicular dependencies, +them in the current app. This includes other symbols imported by these modules. Scarpet supports circular dependencies, but if symbols are used directly in the module body rather than functions, it may not be able to retrieve them. Returns full list of available symbols that could be imported from this module, which can be used to debug import issues, and list contents of libraries. @@ -1382,9 +1385,57 @@ issues, and list contents of libraries. calls a user defined function with specified arguments. It is equivalent to calling `function(args...)` directly except you can use it with function value, or name instead. This means you can pass functions to other user defined -functions as arguments and call them with `call` internally. And since function definitions return the defined +functions as arguments and call them with `call` internally. Since function definitions return the defined function, they can be defined in place as anonymous functions. +#### Passing function references to other modules of your application + +In case a function is defined by its name, Scarpet will attempt to resolve its definition in the given module and its imports, +meaning if the call is in a imported library, and not in the main module of your app, and that function is not visible from the +library perspective, but in the app, it won't be call-able. In case you pass a function name to a separate module in your app, +it should import back that method from the main module for visibility. + +Check an example of a problematic code of a library that expects a function value as a passed argument and how it is called in +the parent app: +``` +//app.sc +import('lib', 'callme'); +foo(x) -> x*x; +test() -> callme('foo' , 5); +``` +``` +//lib.scl +callme(fun, arg) -> call(fun, arg); +``` + +In this case `'foo'` will fail to dereference in `lib` as it is not visible by name. In tightly coupled modules, where `lib` is just +a component of your `app` you can use circular import to acknowledge the symbol from the other module (pretty much like +imports in Java classes), and that solves the issue but makes the library dependent on the main app: +``` +//lib.scl +import('app','foo'); +callme(fun, arg) -> call(fun, arg); +``` +You can circumvent that issue by explicitly dereferencing the local function where it is used as a lambda argument created +in the module in which the requested function is visible: +``` +//app.sc +import('lib', 'callme'); +foo(x) -> x*x; +test() -> callme(_(x) -> foo(x), 5); +``` +``` +//lib.scl +callme(fun, arg) -> call(fun, arg); +``` +Or by passing an explicit reference to the function, instead of calling it by name: +``` +//app.sc +import('lib', 'callme'); +global_foohandler = (foo(x) -> x*x); +test() -> callme(global_foohandler, 5); +``` + Little technical note: the use of `_` in expression passed to built in functions is much more efficient due to not creating new call stacks for each invoked function, but anonymous functions is the only mechanism available for programmers with their own lambda arguments @@ -3550,6 +3601,10 @@ Required arguments: `entity, amount, source, attacking_entity` It doesn't mean that all entity types will have a chance to execute a given event, but entities will not error when you attach an inapplicable event to it. +In case you want to pass an event handler that is not defined in your module, please read the tips on + "Passing function references to other modules of your application" section in the `call(...)` section. + + ### `entity_load_handler(descriptor / descriptors, function)`, `entity_load_handler(descriptor / descriptors, call_name, ... args?)` Attaches a callback to when any entity matching the following type / types is loaded in the game, allowing to grab a handle @@ -4075,6 +4130,10 @@ handle_event('tick', _() -> foo('tick happened')); // built-in event handle_event('tick', null) // nah, ima good, kthxbai +In case you want to pass an event handler that is not defined in your module, please read the tips on + "Passing function references to other modules of your application" section in the `call(...)` section. + + ### `signal_event(event, target_player?, ... args?)` Fires a specific event. If the event does not exist (only `handle_event` creates missing new events), or provided argument list @@ -4740,6 +4799,9 @@ algorithm has taken in to account last time mobs spawned. Schedules a user defined function to run with a specified `delay` ticks of delay. Scheduled functions run at the end of the tick, and they will run in order they were scheduled. +In case you want to schedule a function that is not defined in your module, please read the tips on + "Passing function references to other modules of your application" section in the `call(...)` section. + ### `statistic(player, category, entry)` Queries in-game statistics for certain values. Categories include: