Idea

Serge A avatar image
8 Likes"
Serge A suggested Serge A edited

Syntax to create node-local functions / function literals

Lack of the local function abstraction is IMO the single most important factor which leads to unmaintainable FlexSim code. In the wild, I routinely see nodefunctions with over 1000 lines or code, 10+ levels of code nesting, and cyclomatic complexity through the roof (100+).

FlexSim already supports fsnodes and nodefunctions, which are text nodes with chunks of code with two different parameter-passing conventions, and usercommands, which are basically the same thing + metadata. Usercommands are the closest thing to "functions" in other languages.

The problems with relying only on usercommands are:

  • usercommands pollute the global namespace and are suggested by autocomplete everywhere
  • usercommands are rather unwieldy to create¹

¹ Creating a "nodefunction" in MAIN:/project/exec/usercommandlist takes approximately 20 mouse clicks (!), a couple of keyboard shortcuts, not counting writing the function itself and all the boilerplate.

There are also "applicationcommands", which is a fancy way to hide nodefunctions from the user and exclude them from autocomplete. The problems with applicationcommands are essentially the same:

  • they share the same global namespace
  • they're only slightly easier to create
  • they're not supported by function-call syntax, but should be called by name through applicationcommand().

Eventually, users prefer copy-pasting their code rather than going through the hoops to define nodefunctions in FlexSim way. It should be possible to write something like this in any nodefunction:

var localFunction = function(type varname, …) { /* use varname immediately */ }
// ...
localFunction(somevalue);
// ...

Technically, it is already possible to craft "local functions". FlexSim supports at least three kinds of function-like objects: to be called by executefsnode()/applicationcommand(), nodefunction()/applicationcommand(), and as user commands respectively. All these objects can be constructed and destroyed at runtime. See lambda() hack below.

This solution is far from elegant (lots of boilerplate, no syntax highlighting support, necessity to manually escape strings, no autocomplete), but it works. FlexScript is only one step away from having a normal way to define functions.

The proposal is to allow this syntax (or similar):

var mycmd = function() {
    for (int i = 1; i <= 3; i++) {
        pt("HELLO FLEXSCRIPT WORLD\n");
    }
};

mycmd();

P.S. lambda() hack

Please find attached a user command lambda(fn) and its companion purgelambda([int]), where fn can be either an existing nodefunction, or a string with the function code. Positional arguments can be referred to as %1, %2, ...:

flexsim-functools.lambda.fsx

flexsim-functools.purgelambda.fsx

You may also get code snippets from

https://pastebin.com/BXUGZMNp

Usage:

var mySumFn = lambda("return someflexsimcommand(%1 + %2);");
passFunctionAsParameter(mySumFn);
purgelambda();

lambda() is a hack, but it's a necessary evil because Flexscript functions ("commands") are not first class and cannot be passed as values. While code chunks ("nodefunctions") are first class, they cannot be invoked the same way as commands.

Something like this should really be part of the platform. It should be possible to define functions in-code. It should be possible to define function with a limited scope of visibility. Invocation syntax for commands and nodefunctions should be unified. It should be possible to pass user commands as arguments to other functions.

flexscriptfeature request
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

1 Comment

·
Matthew Gillespie avatar image
2 Likes"
Matthew Gillespie commented

I think this is an awesome idea and I would love to see it happen.

You didn't mention using the function_s() command which is the current best practice. You specify an object, the name of a flexscript node inside the object's eventfunctions node, and a list of Variant parameters. This is how a lot of the objects in the tree are set up, for example:

5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

Write a Comment

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

Your Opinion Counts

Share your great idea, or help out by voting for other people's ideas.