Here's one that definitely takes more than 5 minutes of your time:
user defined functions and
function libraries It sounds complex but it's actually simple, it's mostly string handling/replacement:
function(fname, /#definition#/) - register a function definition (code) for a new function
(just saves the definition as a string, no parsing)call(fname, arg1, arg2, ...) - call a used-defined function
(just replaced by the definition on first-pass parsing)using(fieldName) - load [fieldName] field which would contain a set of function definitions (save() variables could also be there)
The end goal would be to have libraries of user-defined functions that could be developed, maintained and shared by the community.
examples:Simple example with min/max functions (I know they exist in Math(), this is just an example):
function(max, /#if(isequal([P1],[P2],5),[P1],[P2])#/)
function(min, /#if(isequal([P1],[P2],5),[P2],[P1])#/)
Where [P1],[P2]...[Pn] are the function parameters that will be replaced when the function is called (simple string replace)
Usage:call(max, 10, 15) => returns 15
call(min, \[last played\], 1) => this replaces [P1] with [Last Played], which is then interpreted as the actual field. Should be the same as "call(min, [last played], 1)"
Alternatively (better), you could get rid of Call() by just detecting that this is a known/defined function:
max(10, 15) => returns 15, same as call(max, 10, 15)
Function library:We could store a bunch of function definitions in a Field, for instance in [Functions]. To use this function library in other places we would just import the field at the top of our code:
using(functions)/
min(100,10)
Simply doing
"[functions] min(100,10)" could also work, but it would produce a few newline chars on the output. Importing with
Using() would load the definitions while suppressing all output, avoiding that problem.
The [functions] field could actually be a predefined field for this, and it would be automatically imported if it exists. The user could still import other fields with
Using(). This would make all this much easier to use in any place where Expressions can be used, such as for sorting, filtering, etc, without having to explicitly type "using(functions)"
Notes and caveats:- recursive functions probably cannot be allowed
- functions calling other functions should however work, as long as the call stack doesn't result in a loop
- function definition order should not matter, but the case where F1() calls F2(), but F2() is defined after F1() needs to be handled.
- since this is simple string replacement, arguments can be simple values, lists, fields, expressions, etc.
- performance should not be affected by having large function libraries, as, again, all this would just (mostly) work via string replacement
- redefining a user-function should replace the definition, but redefining a system function should probably not be allowed
- the predefined [functions] fields could be loaded once, systemwide, at MC startup (and reloaded when it's saved/changed) (this would work for function definitions but not for save() calls which require the current context to be a File)
- a library field such as [functions] can also include other using() calls. This way the [functions] would be a global auto-loading field for all user code.
...Too complex?
Thanks!