Hi Kevin,
I'll start by answering your specific questions, from both posts, and then by
showing you example code, and if you still have questions, I can elaborate in
another post.
There are two methods to call M code, function and procedure (or routine).
The function method returns a result from the call to the M code, it is a function
that ends with a QUIT with an argument. The procedure method doesn't return
a result, it is a function that ends with a QUIT without an argument. Both methods
can be called synchronously, or asynchronously, the latter is achieved by passing a
JavaScript function with a specific format, as the last argument to the function or
procedure method.
They can also be called in two different ways; either by passing the input in a single
JavaScript object, or by passing them as separate arguments directly to the method.
The first will result in a return of an output JavaScript object, with more info than just
the result from the function, and the second will return just the result from the function,
or in the case of the procedure method, it will always return the JavaScript undefined
object. The second is also modestly faster. For some Nodem methods, using the JavaScript
input object is very useful, because a single call can return enough info to avoid having
to make an additional call to get that same info, but with the function and procedure
methods, it's probably best to call them passing the arguments separately by position,
as it's faster and you really only care about the result.
Nodem also has a method called help, and if you call it with no arguments it will list
all of its method APIs, and you can call it with a single string that is the name of a method,
and it will give you a quick API reference for that method. E.g. `ydb.help('function');` would
return info about the function method.
```
So it looks like the arguments can be:
- a string (or is that an array of strings?)
- A number (or an array of numbers?)
- Any arbitrary array
```
This is documenting the use of the JavaScript input object, and all it is saying is that to pass
arguments to the function, you create a key called arguments, and a value that is an array.
The array can be empty, which is the same as if you didn't pass an arguments key at all. The
array then is just the arguments you want to pass to the function, so they can be a mix of
strings and numbers, just like in M. I'll go over call by-reference a little later.
```
Questions:
- If a mumps function takes three
variables, e.g. MYFUN(A,B,C), and the arguments is a string array, does
element 0 go to A, 1 to B, and 2 to C? Or would A simply be found to be
an array with 3 elements, and B and C being undefined?
- In
mumps, to get an array as an output of a function, one has to pass a
variable by reference. E.g. DO MYFN(.OUT,5,6). Is this supported in
nodem?
- My suspicion is that the result of the function is going
to be limited to a literal string. If so, could full multi-var array be
serialized and returned that way, and then converted to json in nodem?
If so, what functions would be used on mumps side and on node side?
- Since arguments appear to support an arbitrary array, how would nodem handle if I passed an array of json arguments?
```
- The first option you mention. But you are using local M variables as arguments, and the normal passing of arguments from Nodem to M would pass data from JavaScript to M, so by the methods already described, can only be a string or number, originating from JavaScript. In the next section I'll describe how to do this and how to do it calling by-reference. But, if your example used string arguments instead, it would look like this, e.g. `ydb.function({function: 'MYFUNC', arguments: ['A', 'B', 'C']};` or `ydb.function('MYFUNC', 'A', 'B', 'C');`
- Yes it is. Both passing arguments that are M local variables, as discussed in 1, and passing arguments that are M local variables by-reference are supported.
- The result of the function will be whatever you pass as an argument to QUIT in the explicit function in M. So a string or number. When calling a function using the JavaScript input object, the result will be a JavaScript output object, but the return value of the M function will still just be a string or number, in this case returned as the value of the result property. An array will not be returned from M. I think you are asking about how to call a function, passing an argument that is an M local variable, by-reference, and how to get at those values. I will go over that in a later section.
- They would be converted to strings. Quick aside, JSON is just a string. It's a string that represents a particular structure, specifically the structure of a JavaScript object or array. I think you might be conflating terms here, and you are asking what happens if you pass arguments to the function method in the arguments array which are themselves JavaScript objects (not JSON). If so, they will be converted in to strings by the JavaScript engine. Here are examples from the Node.js REPL to help illustrate that. E.g. `{'key': 'value'}.toString()` will return '[object Object]' and `['value1', 'value2'].toString()` will return 'value1,value2'. There is one exception to this. When passing a specially-formatted object as an argument to a function or procedure, it will not be converted in to a string, as Nodem will process it first, in order to convert the arguments you pass in it to YottaDB, so that they can be passed as variables with call by-variable or call by-reference.
Before I go over how to pass M local variables by-variable and by-reference, I'll move on to
respond to your next email in this thread. I have no idea who sent you a private message
about this, but nothing was added to my repo to address your questions. That information
has been there for over a decade. As I've been writing this response as I'm reading your posts,
I can see that the examples I would have provided are already there from my README.md and
copied in your second post. So I'll just say two more things. First, here is the answer to your last
question.
```
QUESTION:
Against this backdrop of confusing (to me) nomenclature, Is it correct to consider that the type variable
described above is where the name of a variable is passed? There is a
helpful example provided for passing by reference, but none for passing
by variable.
```
Yep, that's exactly right. When you normally pass a string, number, or variable as an argument
in Node.js, you are passing JavaScript things, so the variable will be dereferenced in Node.js, not
in YottaDB. That's why you have to use the special JavaScript object, so that you can annotate the
type, to tell Nodem that you are not passing data from JavaScript, you are passing data from within
the M engine. When the `type` property is `variable` then the string that you pass to the `value`
property, is passed to the M function as the name of an M variable, which is what you want. When
the `type` property is `reference` then the string that you pass to the `value` property, is passed to\
the M function as the name of an M variable, prefixed with a `.`, hence it's being called by-reference,
not by value.
I think the terminology is tripping you up a bit, because in the M standard, which only defines
call by-value and call by-reference, the handling of an argument that is passed as a variable, without
a `.` in front of it, is dereferenced to its value, prior to the actual call to the function. So calling a function
as `write $$label^function("string")` is the same thing when binding arguments to parameters and
making the actual call, as `write $$label^function(arg)` is, when arg was previously set to "string". They
are the same thing as far as argument passing semantics. But when you add a `.` to the front of that
variable, you are no longer binding the value of that argument to the parameter in the function (the M
Standard uses the terms 'actual parameter' and 'formal parameter' to refer to 'argument' and
'parameter' in this discussion), you are binding a reference to that variable in the symbol table, to the
parameter in the M function, allowing it to treat it as a regular M array with all of its nodes, rather than
simply containing a copy of the value of the variable in the argument.
Second, Nodem has a debug tracing built in to it, so if you call the configure method, and pass it a JavaScript
object, that contains a property named 'debug', and a value of 0, 1, 2, or 3 (other things work, but these
numbers are the simplest), then you can see a trace of everything Nodem is doing, in the C++, C, and
M code. A value of 0 is no debug output, the default, and then 1, 2, and 3 are increasing levels of debug
tracing. By doing this, you can see what Nodem is doing with your JavaScript data at every point, and with it
set up at 3, you can see what it's doing in the M code even, like how your JavaScript data is being used in
your M function call.
I hope this helps, and again, if you have any other questions, let me know.
David Wicksell
Fourth Watch Software LC