deff in-line definition of a (anonymous) function in Scilab language

## Syntax

                deff(funcHeadline, funcBody)
                deff(definition)
                deff("[r1, r2, ...] = myFunc(in1, in2, ...)", funcBody)
                deff "r = myFunc(x,y) r = x^2 - y"
                deff "r = myFunc(x,y) x^2 - y"
                deff("r = @(x,y) x^2 - y")      // as anonymous container's element

                myFunc = deff(funcHeadline, funcBody)
                myFunc = deff(definition)
                myFunc = deff("[r1, r2, ...] = fakeName(in1, in2, ...)", funcBody)
                myFunc = deff("r = fakeName(x,y) r = x^2 - y")
                myFunc = deff("r = fakeName(x,y) x^2 - y")
                myFunc = deff("r = @(x,y) x^2 - y")

## Arguments

x, y, in1, in2, ...
  input arguments of the defined function. This one can have any number of input arguments, from 0 to any N.

r, r1, r2, ...
  Output results of the defined function. This one can have any number of output results, from 0 to any M. If any, all output arguments must be explicit = written on the left-hand-side of the function name.

funcHeadline
  Single string: Function's headline = its first line giving the local function's name and the lists of its right-hand-side input arguments and left-hand-side output arguments. Examples:
  - `"myFunction(x,y)"` : no output
  - `"r = myFunction(x,y)"` : single output
  - `"[a,b] = myFunction(x,y)"` : two outputs. Etc..
  Please note that a) the `function` keyword must not be provided. b) If any, writting output arguments in the left-hand-side part of the headline is mandatory.

funcBody
  a vector of texts = Scilab instructions of the function's body, in the order they must be executed. These instructions must define and assign the value of all output arguments. No trailing "endfunction" keyword is expected.

  This vector is expected when deff(…) is called with two input arguments.

  Single or double quotes included in instructions must be doubled to be protected.

definition
  Single text or vector of texts, including both the function's headline and body.
  - If it's a vector, it is equivalent to `definition = [funcHeadline ; funcBody]`.
  - Otherwise, the one-string definition is equivalent to `funcHeadline + " " + strcat(funcBody,"; ")`.
  Please see the Description and Examples sections.

myFunc
  Public name and identifier of the defined function, as implicitly returned in the current environment, or explicitly assigned to the deff(…)'s output variable.

  When deff(…) is called without explicit output argument but as an element of a container or as input argument of another function, it is implicitly assigned to this element or argument, which is anonymous. It is then an anonymous function. Example:

  `L = list(3, deff("r=noName(x) x.^2+1"), "Hello");`. The result of deff(…) is assigned to L(2). Then, `L(2)(3.5) // ➜ 13.25`.

## Description

deff(…) can be used to define a single function from Scilab instructions provided through a matrix of text, instead of through any external text file of instructions written in a `function … endfunction` block to be executed.

A source file of Scilab code can include the definition of several public functions. This is not possible with deff(…): Only one public function can be defined. However, as with a file, the body of the defined function can include one or several `function … endfunction` blocks defining some nested private functions.

Whatever is the deff(…) syntax used to provide the source code (see below), if this one includes a syntax error, deff(…) will yield a compilation error and stop.

### Providing the source code

deff(funcHeadline, funcBody) (2 inputs) and deff([funcHeadline ; funcBody]) (single concatenated input) are equivalent.

When `funcBody` is made of only one (short) string, it may be glued to and passed with the `funcHeadline`, as a one-line function definition. Examples:

`deff("[a,b] = myFunction(x,y) a = x.^2; b = x-y;")`
`deff("r = myFunction(x,y) r = (x-y).^2")`. This can even be simplified into
`deff("r = myFunction(x,y) (x-y).^2")`
`deff("myFunction(x,y) disp(x.^2 - b)")`

When the result of deff(…) is assigned to or inserted into any anonymous element of a container, then it comes that the pseudo-name `fakeName` defined in the `funcHeadline` has no role at all, and could in no way be used to call the function. This name can then be replaced with the "@" character in the `funcHeadline`, to highlight that the defined function becomes anonymous.

### Identifier of the defined function

The identifier is the actual word (name) to use to call the defined function. The 3 following cases are illustrated in examples.

When the defined function is not expected as a assignable result, its identifier is returned directly in the calling environment. Its public name is then the name used in the headline of the provided source code.

Otherwise, when deff(…) is called with an explicit output argument, the name of this one becomes the only actual public function's identifier. As a consequence, the function name used in the source code can't be used to call it. It becomes a pseudo-name. For this reason, the "@" symbol (standing for "anonymous") can then be used in the function code's headline, instead of any valid function's name. Of course, nothing prevents to use an output name identical to any valid function name defined in the headline. But it's not mandatory.

The last case is using deff(…) as an element of a container, for instance when defining or inserting into a list, or as input argument of another function. Then deff(…) works in an assignable way. It returns the identifier of the defined function and assigns it to the considered list element or input argument. These ones are nameless, since the `deff(…)` call is an expression. The defined function then becomes really anonymous.

## Examples

### Unassigned functions

                    deff('x = myplus(y,z)', 'x = y+z')
                    myplus(1,%i)

                    deff('[y, z] = mymacro(x)', ['y = 3*x+1'; 'z = a*x + x.^2'])
                    a = 3;
                    [u, v] = mymacro(2)

    --> deff('x = myplus(y,z)', 'x = y+z')
    --> myplus(1,%i)
     ans  =
       1. + i

    --> deff('[y, z] = mymacro(x)', ['y = 3*x+1'; 'z = a*x + x.^2'])
    --> a = 3;
    --> [u, v] = mymacro(2)
     v  =
       10.

     u  =
       7.

With some single input and output:

                    clear myFunc
                    source = ["r = myFunc(x,y)" ; "r = x.*(x-y)"]
                    deff(source)
                    myFunc(3, -2)

    --> source = ["r = myFunc(x,y)" ; "r = x.*(x-y)"]
     source  =
      "r = myFunc(x,y)"
      "r = x.*(x-y)"

    --> deff(source)
    --> myFunc(3, -2)
     ans  =
       15.

Same example with a one-line definition, that then allows a console-oriented syntax (without optional deff parentheses, but with still mandatory delimiting quotes):

                    clear myFunc
                    deff "r = myFunc(x,y) r = x.*(x-y)"
                    myFunc(1:3, -2)

    --> deff "r = myFunc(x,y) r = x.*(x-y)"
    --> myFunc(1:3, -2)
     ans  =
       3.   8.   15.

For a one-line direct definition with a single output, we can even omit the "r = " duplicate in the body:

                    clear myFunc
                    deff "r = myFunc(x,y) x.*(x-y)"
                    myFunc(1:3, -2)

    --> deff "r = myFunc(x,y) x.*(x-y)"
    --> myFunc(1:3, -2)
     ans  =
       3.   8.   15.

Function with no assignable output: Note also the usage of doubled quotes to protect them in the definition string:

                    clear myFunc
                    deff("myFunc(x, y) messagebox(prettyprint(x.*(x-y), ""html"",""""))")
                    myFunc([1 2 ; 3 4], -2)

### Defined function assigned to a recipient

Let's keep similar examples as above:

                    clear myFunc actualName
                    actualName = deff("r = myFunc(x,y) x.*(x-y)")
                    isdef(["myFunc" "actualName"])
                    actualName(1:3, -2)
                    myFunc(1:3, -2)

    --> actualName = deff("r = myFunc(x,y) x.*(x-y)")
     actualName  =
    [r]=actualName(x,y)

    --> isdef(["myFunc" "actualName"])
     ans  =
      F T

    --> actualName(1:3, -2)
     ans  =
       3.   8.   15.

    --> myFunc(1:3, -2)
    Undefined variable: myFunc

Since the "internal" function name is fake, we can use "@" instead (the "@" character is not allowed in actual function names):

                    clear actualName
                    actualName = deff("r = @(x,y) x.*(x-y)");
                    actualName(1:3, -2)

    --> actualName = deff("r = @(x,y) x.*(x-y)");
    --> actualName(1:3, -2)
     ans  =
       3.   8.   15.

Now, let's directly assign the created function to a nameless recipient. Although the function becomes anonymous, we can still call it:

                    L = list("abc", deff("r = @(x,y) x.*(x-y)"), %z);
                    L(2)(1.1:4, -2.1)
                    // We can extract and set a name to the anonymous function:
                    Abc = L(2)
                    Abc(1.1:4, -2.1)

    --> L = list("abc", deff("r = @(x,y) x.*(x-y)"), %z);
    --> L(2)(1.1:4, -2.1)
     ans  =
       3.52   8.82   16.12

    --> Abc = L(2)
     Abc  =
    [r]=Abc(x,y)

    --> Abc(1.1:4, -2.1)
     ans  =
       3.52   8.82   16.12

Finally, let's use deff() to directly define and pass a function as an input argument of another function:

                    function r = test(txt, x, theFunc)
                        r = x + theFunc(txt)
                    endfunction

                    test(rand(2,3), 0.7, deff("r = @(M) sum(size(M).^2)"))

    --> test(rand(2,3), 0.7, deff("r = @(M) sum(size(M).^2)"))
     ans  =
       13.7

In this example, the passed function is anonymous in the calling environment, but is assigned and gets its "theFunct" name from inside the called function.

## See also

- function
- exec
- getd
- genlib
- jdeff
- jcompile

## History

6.0.0

- The input option `opt="c"|"p"|"n"` is no longer available.
- The defined `newfunction` is now of type 13 (instead of 11).

6.1.1

- Output optional argument added. Anonymous functions can be defined.
- Single input argument supported, concatenating the function headline and body.
- Single string syntax supported, like `deff "r = myFun(x,y) x.^2-y"`
- "@" function's pseudo-name supported.