Thank you! It looks like %set and %get were documented at one time, but got lost in the move to $system.external.

These methods work differently in each language. For example, here's how to build and access a 2-dimensional string array in DotNet, Java, and Python (you can run each example in the Terminal):

 //================================================================
 // DOTNET
 //================================================================
 set arr = $system.external.getDotNetGateway().new("string[2,3]")
 for x=0:1:1 {for y=0:1:2 {set chr=$CHAR(65+(x*3+y)) do arr.%set(x,y,chr) }}
 do arr.%set(1,1,"x") // change value(1,1) from E to X
 for x=0:1:1 {for y=0:1:2 {write !,"("_x_","_y_")="_arr.%get(x,y)_" " }}
 kill arr  

//================================================================
 // JAVA
 //================================================================
 set arr = $system.external.getJavaGateway().new("String[2][3]")
 for x=0:1:1 {for y=0:1:2 {set chr=$CHAR(65+(x*3+y)) do arr.%get(x).%set(y,chr) }}
 do arr.%get(1).%set(1,"X") // change value(1,1) from E to X
 for x=0:1:1 {for y=0:1:2 {write !,"("_x_","_y_")="_arr.%get(x).%get(y)_" " }}
 kill arr

 //================================================================
 // PYTHON
 //================================================================
 set gw = $system.external.getPythonGateway()
 set arr = gw.new("list")
 for x=0:1:1 {do arr.append(gw.new("list")) for y=0:1:2 {set chr=$CHAR(65+(x*3+y)) do arr.%get(x).append(chr) }}
 do arr.%get(1).%set(1,"X") // change value(1,1) from E to X
 for x=0:1:1 {for y=0:1:2 {write !,"("_x_","_y_")="_arr.%get(x).%get(y)_" " }}
 kill arr

Just thought I should mention that there is a way to use legacy gateway code completely as-is, by using the Recast proxy generator rather than $system.external syntax. This was developed for Ensemble productions, but it should work for any code that uses the old proxy generator (he says, sticking his foot in his mouth again. No, I haven't actually tried it, but...)

To generate Recast proxy classes, set the following global:
  set ^%SYS("Gateway","Remote","Recast",namespace)=1
or
  set ^%SYS("Gateway","Remote","Recast")=1
then re-import all the proxy classes. The first global governs Recast behavior for one namespace only while the second global governs Recast behavior for all namespaces that don't have their own setting. The import utility will automatically mark all the old-style proxy classes as out-of-date and re-import all the classes in the inheritance hierarchy.
All of the proxy classes have to be regenerated together. The Recast generator creates drop-in replacements for the old proxies, but it actually uses the new dynamic proxy technology under the hood, so they can't be mixed with the old Caché-style proxy classes.

This still begs the question of how to deal with arrays using $system.internal. I think you can round-trip just about any object by using inverse proxies on the .NET side. Can't go into that now because I'm supposed to be enjoying my vacation and my wife is giving me that look.

The "old code" you've posted should work without changes.  The main difference between the Object gateway and $system.external is in how you create the proxy. For example, to connect and create a "test" object:

set gateway = $system.external.getDotNetGateway()
do gateway.addToPath(myPath_"\DotNetGatewaySamples.dll")
set test = gateway.new("remote.test.Person")

Once you've created the proxy, it should work just as it always has.

Excellent article!
One quibble: it is actually possible to use fields like departure_time and stop_name as subscripts. Those fields will be imported as string subscripts, which can contain any character (including nonprinting characters). For example, the following code works fine, and automatically imports departure_time as a string subscript:


  # stoptimes -> [stop_id] -> [trip_id] -> [stop_sequence] -> [departure_time]=None
    for row in reader:
        iris.set(None, "stoptimes", row[3], row[0], row[4], row[2])

Congratulations! You're the first person to notice that since I wrote the Python book ten years ago.  Yes, I copied those entries from the Perl book and forgot to change the function names. Obviously "Perl binging" is not a typo.

I'll probably fix the old Python book  just as I finish writing the new Python book, covering the upcoming InterSystems IRIS Native API for Python. So please look forward to a new book and a brand new set of typos! With your help, perhaps we can catch them a bit sooner this time...