Duck-Typing (or Duct Taping) Dynamic Objects in C#

I've been delving into DLR and dynamic types as of late; in particular, how to enforce a static "contract" (an interface per se) on a dynamic type. During my perusal of blogs and articles, I came across an article by Tobi that delved into what I was trying to do, but not in a generic fashion. The interesting bit of it is that Tobi referenced another open source project called the Castle Project. This project, among other things, has some utility methods that allow developers to create class proxies and implement interfaces at runtime.The proxied objects could then have their method and property calls specially handled by an IInterceptor implementation. So, after reviewing of the code and a little bit of hacking, I came up with runtime duck typing solution:

Python Code:

import clr 

class Dragon:
def Quack(self):
print "ROAR!"

dragon = Dragon()

C# Code:

public interface Duck
{
void Quack();
}

public class Cow
{
public void Quack()
{
Console.WriteLine("Moo?");
}
}

class Program
{
static void Main(string[] args)
{
ScriptEngine pythonEngine = Python.CreateEngine();
ScriptRuntime runtime = pythonEngine.Runtime;
ScriptScope scope = runtime.ExecuteFile("hello.py");
IDynamicObject dynamicObject = (IDynamicObject)scope.GetVariable("dragon");

// I can't figure out how to do this without the runtime?
// Using GetMetaObject and building an expression tree?
Duck dragon = DuctTapeHelper.DuctTape<Duck>(dynamicObject, runtime);
Duck cow = DuctTapeHelper.DuctTape<Duck>(new Cow());

// Duck Type!
dragon.Quack();
cow.Quack();
}
}

Notice that neither "Cow" or "Dragon" implement the "Duck" interface, but at runtime, an interface proxy is generated to allow them to become Ducks!

Incidentally, another potential way to do this, without the dependency on the Castle Project utilities, is to use reflection to generate a IronRuby/IronPython script that implements an interface proxy.

Here's the full source code to my version of the DuctTape project. I am packaging the various projects from DLR and Castle into it as well. The code is nowhere near complete; it is just a functional prototype to make sure the concepts actually work! I feel that it could be done better through expression trees, but I couldn't figure out how to use an Expression tree to call into a dynamic method on IDynamicObject. Please let me know if you have more insight into this, as I am still a DLR noob.

 

Completely Unrelated:

Does anyone know of a good way to embed code into a blog? As you can see, my line breaks become all messed up with whatever tool I use (I use Live Writer with Paste from Visual Studio or Source Code Snippet).

Solved:

Blogger has some silly "Convert line breaks" option that is defaulted to Yes. As a result, it completely mangles all line breaks if you have a <pre> tag in your post body. Turn that off, and all is well.

Microsoft's DLR and Mono bring Python and Ruby to Android

device

With my recent work on porting Mono to Android, I began needing a way to create Java classes and invoke their various methods from C#. I had read briefly about the Dynamic Language Runtime and upcoming C# support for dynamic types; so that naturally led to me considering implementing a JNI-P/Invoke interop layer that allows access to Java/Dalvik code through C# and vice versa. However, I wasn't sure if the DLR would even run on Mono, but I was pleasantly surprised. Support for the DLR was added to Mono around a year and a half ago!

After copying the necessary DLLs over to the phone, I was able to run the simple ipy.exe console application that comes with the DLR source code. The neat thing I discovered while perusing through the documentation is that IronRuby and IronPython are actually compiled into CIL byte code and thus eventually native code! Anyhow, as you can see, IronPython is working dandily on the phone. [1]

The Dynamic Language Runtime is probably the coolest new toy in the .NET arsenal since lambda expressions. Couple the DLR with the new dynamic keyword in C# 4.0, and you can invoke dynamic languages from C# as easily as you can access .NET classes from IronPython or IronRuby![0]

Now to get back to implementing Java interop...

 

[0] The dynamic keyword basically provides compile time parsing of an expression tree, but the expression isn't actually validated until runtime.

[1] Though Mono + DLR is clocking in at a hefty 13mb in files. But, applications will soon be installable onto the SD card so the storage constraints will be a moot point.

JNI in Android (and a foreword of why JNI Sucks)

wall-smaller

Quick Preface: You do NOT need root to create and use a shared native library (.so) in Android from your Java application.

I had never tried Java Native Interface until today. And I must say, it completely sucks. Not only is the header generation/implementation nontrivial and tedious, JNI is inherently broken in that it is not architecture/platform nonspecific. So I proudly present to you my list of why JNI sucks.

  • You can't access arbitrary functions in arbitrary DLLs. JNI requires that you write a glue C/C++ layer to do whatever you want to do natively.
  • On Android, your glue layer must contain a JNI_OnLoad function that explicitly register every method that needs to be made available to the JVM. The JVM can't simply check the export tables and intelligently import it.
  • Since developers must write a glue layer, you must also compile and package that glue layer per platform you are targeting. This design is absurd because platforms can have different CPU architectures and different Operating Systems, and still support similar calls in the similar libraries. For example:
    • OpenGL ES (libGLES_CM). On Windows Mobile it is called libGLES_CM.dll. On Linux/Android it is called libGLES_CM.so. These libraries have the same "undecorated" library name, and also contain the same functions with the same signatures. Unfortunately due to how how terrible an implementation JNI is, the same Java application would not work on every platform.
    • Standard System Libraries on Linux or Windows (libc, libdl, libm, ole32, kernel32, etc) - Once again, need to compile libraries per architecture (ARM, x86, x64, MIPS, etc) to use the common/base functions that would be available on the platform (GetWindowEx, statfs, etc).
  • Write once, run anywhere. (Given that you are willing to do multiple cross compiles and embed multiple native binaries into a single package and unpack the appropriate one at runtime.)

For amusement's sake, let's look at what a C# PInvoke looks like versus JNI on Android. Suppose we want to clear the screen in OpenGL:

C#:

Just declare the method signature and the DLL. Simple! Call that like any other method in C#. (Note that the managed executable generated by this code works on both Android or Windows Mobile. Yes, I tested it.)

[DllImportAttribute("libGLES_CM")]
public static extern void glClearColor(float red, float green, float blue, float alpha);

JNI? Let's start out by declaring it.

public static native void glClearColor(float red, float green, float blue, float alpha);

Not done yet! Now the fun begins. Drop to a command prompt and go to the bin directory of your project: javah com.koushikdutta.JNITest.JNITestAcitivity. Now we have a generated header file, com_koushikdutta_jnitest_JNITestActivity.h, that looks like this:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_koushikdutta_jnitest_JNITestActivity */

#ifndef _Included_com_koushikdutta_jnitest_JNITestActivity
#define _Included_com_koushikdutta_jnitest_JNITestActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_koushikdutta_jnitest_JNITestActivity
 * Method:    glClearColor
 * Signature: (FFFF)V
 */
JNIEXPORT void JNICALL Java_com_koushikdutta_jnitest_JNITestActivity_glClearColor
  (JNIEnv *, jclass, jfloat, jfloat, jfloat, jfloat);

#ifdef __cplusplus
}
#endif
#endif

Ok, now let's implement the C code:

#include <GLES/gl.h>

JNIEXPORT void JNICALL Java_com_koushikdutta_jnitest_JNITestActivity_glClearColor
  (JNIEnv * env, jclass clazz, jfloat r, jfloat g, jfloat b, jfloat a)
{
    glClearColor(r, g, b, a);
}

You probably thought you were done, didn't you? Sun thinks otherwise. You need to register the function in C code as well. Don't screw up when copy pasting the cryptic method signature strings!

static JNINativeMethod sMethods[] = {
     /* name, signature, funcPtr */

    {"glClearColor", "(FFFF)V", (void*)Java_com_koushikdutta_jnitest_JNITestActivity_glClearColor},
};

extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv* env = NULL;
    jint result = -1;

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        return result;
    }

    jniRegisterNativeMethods(env, "com/koushikdutta/JNITest/JNITestActivity", sMethods, 1);
    return JNI_VERSION_1_4;
}

To be completely fair, jniRegisterNativeMethods is actually a convenience function that is found in libnativehelper.so on Android; I imported that library for the sake of... convenience. Its implementation is as follows (JNIHelp.c in the source):

int jniRegisterNativeMethods(JNIEnv* env, const char* className,
    const JNINativeMethod* gMethods, int numMethods)
{
    jclass clazz;

    LOGV("Registering %s natives\n", className);
    clazz = (*env)->FindClass(env, className);
    if (clazz == NULL) {
        LOGE("Native registration unable to find class '%s'\n", className);
        return -1;
    }
    if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
        LOGE("RegisterNatives failed for '%s'\n", className);
        return -1;
    }
    return 0;
}

You need to load the library in Java code in your class's static constructor.

System.load("/data/data/com.koushikdutta.JNITest/libjnitest.so");

On Android, you must use System.load and provide a full path instead of using System.loadLibrary. This is because loadLibrary only checks /system/lib; it does not search LD_LIBRARY_PATH or your current working directory. Unfortunately, applications can't write to the /system/lib directory (without root).

.NET's P/Invoke is so much easier/better that a third party company (God forbid Sun actually do something to better the Java language) implemented something quite similar for Java, named, *drumroll please*, J/Invoke. Too bad Android doesn't have that. That would be nice.

Also, on Android, you can't do a normal ARM/GCC cross compile to make shared libraries (I've discussed this in a previous blog post). The resultant .so files will not work with Android's linker due to different linker scripts. To create shared libraries for Android, I would highly recommend just creating a subproject in the Android Source code tree and building the tree. Alternatively you can use the handy script found on this page.

Also, remember that the shared library will need to be contained in your APK file and extracted to the file system so it can be accessed. For an example of how that can be done, check out the source code that does something very similar in the Android Mono port.

Incidentally, this learning experience came about as a result of figuring out how to run Mono side by side with Java/Dalvik in the same process.

Windows Mobile Unified Sensor API heads to CodePlex

codeplex_toplogo[36]

At the behest of the development community and colleagues, the Windows Moble Unified Sensor API is now hosted on CodePlex. I will continue blogging about the changes on my website of course, but all the releases and source code must now be retrieved from CodePlex! (CodePlex is pretty awesome by the way... it has support for multiple source control bindings, and the web client repository browser is fantastic. (I use CodePlex for Windows Mobile stuff, and Google Code for Android. It makes sense in my head. [0])

In the following weeks, I intend to do the following:

  • Reexamine the implementation (and possibly even the current interfaces) so it is easier for manufacturers to build devices that can leverage the dizzying array of sensor enabled software that already utilize the Sensor API.
  • Clean up the HTC implementation.
  • Add support for capacitive touch panel to the HTC implementation with the new reversed engineered headers provided by a reader of this blog.
  • Create a few tutorials.
  • Add a FAQ to the CodePlex wiki.

If anyone else is interested in contributing to the Sensor API project, please let me know!

 

[0] The decision on whether to put the Android Mono port on CodePlex or Google Code was a tough one. :)