-
Notifications
You must be signed in to change notification settings - Fork 156
ByRef and params
Support has been added for ByRef parameters. There is no notion of an uninitialized variable in Clojure, so the distinction seen in C# between ref
and out
parameters is irrelevant. The special syntactic form by-ref
wraps local variables in interop calls to indicate a parameter that is to be passed by reference. Upon completion of the call, the local variable will be rebound to the value ‘returned’ from the interop call.
For example, suppose you had the following class defined in C#:
public class dm.interop.C1
{
public int m3(int x) { return x; }
public int m3(ref int x) { x = x + 1; return x+20; }
public string m5(string x, ref int y) { y = y + 10; return x + y.ToString(); }
public int m5(int x, ref int y) { y = y + 100; return x+y; }
}
The following Clojure function, passed an instance of dm.interop.C1
and an Int32
will call the overload of m3
with the by-ref
argument.
(defn f3r [c n]
(let [m (int n)]
(.m3 c (by-ref m))
m))
Note that it is necessary to provide the type hint via (int n)
. Otherwise, the only argument to match would be a ref Object
. This example will use reflection and will match on a first argument of any type that has a method with signature m3(ref int)
. To avoid the reflection, you could type-hint the the variable c
.
To get the other overload, the interop call (.m3 c m)
will do the trick.
For method m5
, consider
(defn f5 [c x y]
(let [m (int y)
v (.m5 c x (by-ref m))]
[v m]))
Then (f5 c1 "help" 12)
=> ["help22" 22]
and (f5 c1 15 20)
=> [135 120]
. In other words, because the m5
call is not resolved at compile-time, reflection will pick the correct overload at run-time.
The same mechanism works for new
expressions.
The syntactic form by-ref
can be used at the top-level of interop calls, as shown. (by-ref
can also be used in definterface
, deftype
and similar mechanisms. See [Defining types](Defining types).) It can only wrap a local variable. Supplying a non-local variable argument or invoking by-ref
in some place other than the top-level of an interop call will cause an exception to be thrown.
Consider the following class:
namespace dm.interop
{
public class C6
{
public static int sm1(int x, params object[] ys)
{
return x + ys.Length;
}
public static int sm1(int x, params string[] ys)
{
int count = x;
foreach (String y in ys)
count += y.Length;
return count;
}
public static int m2(ref int x, params object[] ys)
{
x += ys.Length;
return ys.Length;
}
}
}
Consider calling sm1
. There are overloads with params
args of type object[]
and of type string[]
. The first overload can be invoked by
(dm.interop.C6/sm1 12 #^objects (into-array Object [1 2 3] ))
or
(dm.interop.C6/sm1 12 #^"System.Object[]" (into-array Object [1 2 3]))
The second overload can be invoked by
(dm.interop.C6/sm1 12 #^"System.String[]" (into-array String ["abc" "de" "f"]))
or
(dm.interop.C6/sm1 12 #^"System.String[]" (into-array ["abc" "de" "f"]))
Note that when a type name is given as a string in a type tag, it must be namespace-qualified.
For the combination of by-ref and params
as given by m2
:
(defn c6m2 [x]
(let [n (int x)
v (dm.interop.C6/m2 (by-ref n) #^objects (into-array Object [1 2 3 4]))]
[n v]))