JavaScript Mapping for Parameters and Return Values
Passing Parameters in JavaScript
The parameter passing rules for the JavaScript mapping are very simple: parameters are passed either by value (for simple types) or by reference (for complex types). Semantically, the two ways of passing parameters are identical: it is guaranteed that the value of a parameter will not be changed by the invocation.
Here is an interface with operations that pass parameters of various types from client to server:
struct NumberAndString
{
int x;
string str;
}
sequence<string> StringSeq;
dictionary<long, StringSeq> StringTable;
interface ClientToServer
{
void op1(int i, float f, bool b, string s);
void op2(NumberAndString ns, StringSeq ss, StringTable st);
void op3(ClientToServer* proxy);
}
The Slice compiler generates the following proxy methods for these definitions:
class ClientToServerPrx extends Ice.ObjectPrx {
op1(i, f, b, s, context) { ... }
op2(ns, ss, st, context) { ... }
op3(proxy, context) { ... }
}
abstract class ClientToServerPrx extends Ice.ObjectPrx {
op1(
i:number,
f:number,
b:boolean,
s:string,
context?:Map<string, string>):Ice.AsyncResult<void>;
op2(
ns:NumberAndString,
ss:StringSeq,
st:StringTable,
context?:Map<string, string>):Ice.AsyncResult<void>;
op3(
proxy:ClientToServerPrx,
context?:Map<string, string>):Ice.AsyncResult<void>;
}
Given a proxy to a ClientToServer interface, the client code can pass parameters as in the following example:
const p = ...; // Get ClientToServerPrx proxy...
await p.op1(42, 3.14, true, "Hello world!"); // Pass simple literals
const i = 42;
const f = 3.14;
const b = true;
const s = "Hello world!";
await p.op1(i, f, b, s); // Pass simple variables
const ns = new NumberAndString();
ns.x = 42;
ns.str = "The Answer";
const ss = [];
ss.push("Hello world!");
const st = new StringTable();
st.set(0, ss);
await p.op2(ns, ss, st); // Pass complex variables
await p.op3(p); // Pass proxy
Null Parameters in JavaScript
Some Slice types naturally have "empty" or "not there" semantics. Specifically, sequences, dictionaries, and strings all can be null, but the corresponding Slice types do not have the concept of a null value. To make life with these types easier, whenever you pass null as a parameter or return value of type sequence, dictionary, or string, the Ice run time automatically sends an empty sequence, dictionary, or string to the receiver.
This behavior is useful as a convenience feature: especially for deeply-nested data types, members that are sequences, dictionaries, or strings automatically arrive as an empty value at the receiving end. This saves you having to explicitly initialize, for example, every string element in a large sequence before sending the sequence in order to avoid a run-time error. Note that using null parameters in this way does not create null semantics for Slice sequences, dictionaries, or strings. As far as the object model is concerned, these do not exist (only empty sequences, dictionaries, and strings do). For example, whether you send a string as null or as an empty string makes no difference to the receiver: either way, the receiver sees an empty string.
Optional Parameters in JavaScript
Optional parameters use the same mapping as required parameters. The only difference is that undefined can be passed as the value of an optional parameter or return value to indicate an "unset" condition. Consider the following operation:
optional(1) int execute(optional(2) string params, out optional(3) float value);
The corresponding proxy method is:
execute(
params?: string | undefined,
context?: Map<string, string>):
Ice.AsyncResult<[number | undefined, number | undefined]>;
For optional parameters and optional return values, there is not distinction between null and undefined, both are treated as a not set optional and unmarshall as undefined.