Thursday, February 26, 2015

Nim and Java and C++


This single markdown file, nim_java.md mixes: Nim, Java, and C++. The output is a single executeable that includes the Nim code translated to C, the Nim C runtime, Rusthon code translated to C++, and links to the JVM. This allows you to call Nim and Java functions from Rusthon, and manage passing data between them. For how to load a JAR library, see here.

#backend:c++

import nim
import jvm
jvm.namespace('mymod')

@jvm
class PointSubclass( Point ):
 def __init__(self, x:int, y:int):
  self.set(x,y)

 def show(self):
  print self.getx()
  print self.gety()


def main():
 nim.main()
 p1 = jvm( PointSubclass(1,2) )
 p2 = jvm( PointSubclass(10,20) )
 p1.show()
 p2.show()
 p2.scale( nim_sum(100, 1000) )
 p2.show()

Mixing Nim, Java and C++ in a single binary would normally require some complex build, and running a wrapper generator like Nimrod-Java. But Nimrod-Java has not been updated in a year, and calling JNI through Nim is going to complicate threading.

Nim and Rusthon


Nim is a new language with some very powerful features. Nim's weakness is interfacing with C++ and external threads, Hankiewicz has a good article on some of these issues here. Nim and Rusthon integration helps solve this problem, allowing you to call Nim functions from C++. This works by including your Nim program in the same markdown file along with a Rusthon program. The embedded Nim program is parsed and wrappers are generated for Nim functions that export to C. During the build Rusthon will use Nim to translate the program to C, and GCC is called to compile a staticlib without a main. The static C library is then linked to the final C++ executeable.


markdown source code

nim

proc my_nim_function(a:cint,b:cint,s:cstring): cint {.cdecl, exportc.} =
 echo("calling my_nim_function")
 echo(s)
 echo("a:", a)
 echo("b:", b)
 result = a+b

rusthon

You need to import nim and in your main function call nim.main() before calling any Nim functions.
#backend:c++
import nim

def main():
 nim.main()
 print 'calling nim function'
 s = 'mymessage to nim'
 msg = my_nim_function( 10, 20, cstr(s) )
 print msg
 print 'ok'

program output

running: /tmp/rusthon-c++-bin
calling nim function
calling my_nim_function
mymessage to nim
a:10
b:20
30
ok

Saturday, February 21, 2015

Subclass from Java


You can subclass from a Java class in Rusthon using the C++11 backend. JNI wrappers are generated using Giws and automatically compiled with the final exe by putting the Giws XML inside your markdown project.

Giws only supports regular and class methods, and basic types. Constructors and properties of Java classes are not exposed, and require extra wrapping by hand. Hopefully this will get fixed soon, github issues: constructors, properties

source code: https://github.com/rusthon/Rusthon/blob/master/examples/giws_subclass.md

java

package mymod;

public class A{
 public A(){}
 public void foo(){
  System.out.println("A.foo from java.");
 }
}

public class B extends A{
 public int y;
 public B(){ this.y=420; }
 public void bar(int i){
  System.out.println("B.bar from java.");
  this.y = i;
 }
}

rusthon

The example below shows how the property y (defined in the Java class) is exposed to Rusthon with inlined C++ that directly uses JNI calls. This is not actually the best way to do this, it would be better to write getter/setter functions in Java, and wrap those normally with Giws XML. This way of going direct with inlined JNI is only useful if you were loading a JAR and did not have access to the original Java source code to add the getter/setters.

import jvm
jvm.namespace('mymod')

@jvm
class C(B):
 def __init__(self, x:int):
  self.x = x

 def get_y(self) ->int:
  inline('''
  auto env = getCurrentEnv();
  auto fid = env->GetFieldID(this->instanceClass, "y", "I");
  return env->GetIntField(this->instance, fid);
  ''')

 def hey(self):
  print('hey from rusthon')

c++ output of C

using namespace mymod;
class C:  public B {
  public:
 std::string __class__;
 int  x;
 C* __init__(int x);
 int get_y();
 void hey();
 C(JavaVM* _jvm) : B(_jvm) {__class__ = std::string("C");}
 std::string getclassname() {return this->__class__;}
};
 int C::get_y() {
  auto env = getCurrentEnv();
  auto fid = env->GetFieldID(this->instanceClass, "y", "I");
  return env->GetIntField(this->instance, fid);
 }
 void C::hey() {
  std::cout << std::string("hey from rusthon") << std::endl;
 }

 C* C::__init__(int x) {
  this->x = x;
  return this;
 }

When creating an instance of C you still need to wrap it with the special jvm call so that the Java proxy object is also created.

def main():
 c = jvm( C(999) )
 print c.x  ## x can be used directly, prints 999
 print c.get_y()  ## prints 420
 c.foo()
 c.bar( 100 )     ## sets y to 100
 print c.get_y()  ## prints 100
 c.hey()