Dynamic Language Integration in a C# World

.NET 4.0 introduced the Dynamic keyword in C#4.0, making it simple to have your .NET code smoothly interact with dynamic languages. To find out just how easy it was, Zenon Ochal used C# and IronPython to build a very efficient mathematical expression plotter in double-quick time.

1195-replCalculator.jpg

Microsoft’s .NET 4 framework introduces the ‘dynamic’ keyword in C#, which, as the name suggests, finally brings new ‘dynamic’ features to the programming language. These dynamic features bring several advantages, and the one which I’ll focus on here is the possibility of integrating C# with other dynamic languages, such as IronPython.

Why bother with dynamic features? To show why by illustration, I’m supplying, with this article, a simple application that does a graphical XY plot  of the functions that you enter.

Now we Can Have the Best of both worlds

I’ve been playing around with this new functionality, and I’ll start off by presenting two simple code samples in this article to illustrate how this feature can be used, and then explain how they can be built upon. The first sample calls Python methods from within C#, and the latter calls C# methods from within Python. Whilst the demonstrations are perhaps not very useful in themselves, they give you a start, I  then show how this technique could form the basis of an application that takes advantage of the best features of both languages by providing a more extensive example that finally does something useful: plots out any function you choose, or type in, graphically.

Specifically, I’ll be demonstrating how the use of the dynamic keyword makes it incredibly easy to build a cross-language calculator capable of solving some basic mathematical expressions. Building on that, I’ll give you a brief overview of a more elegant way of combing (or perhaps hybridizing) the two languages, as well as how to extend the basic calculator engine into a read-eval-print loop (REPL), or ‘interactive top-level’ . This can be used for a number of very cool applications (See Ben Hall’s IronRuby REPL to extend SQL Data Generator and his ‘Methodist’ add-in For Net Reflector). I’ll  use this REPL to evaluate more sophisticated functions for a wide range of values, in the graph-plotter.

To run the examples, you need to have Visual Studio 2010 with .NET 4.0 and Iron Python 2.6 for .NET 4.0 installed on your computer.

Calling Python Methods From C#

This first example demonstrates how to access a Python class called Calculator from within C# code. When I originally started writing these demonstrations, the Python class was loaded from an external file, and the resulting program was just a very simple calculator, and these are the steps I went through to build it. However, I later built on this platform and build a function plotter, and the end result of my tinkering was to actually have the Python class loaded and executed in Memory. Once I’ve walked you through the foundation, I’ll go on to elaborate on the final application.

Create the Python Method

This is relevant if you decide you want to keep your python class in a separate file. On the other hand, if you’d prefer to follow my example (which is can be downloaded from the top of this article) and run the python within memory, you can ignore this section and skip further down the article:

  1. Start Visual Studio 2010 and create a new Console Application project with the name DynamicPy;
  2. In the Solution Explorer, right-click the DynamicPy project file, and select Add > New Item > Text file;
  3. In the Solution Explorer, rename the new file to calc.py;
  4. Open calc.py, and define the Calculator class in Python:
  5. Save the file.

Call the Python Method from C#

Now that you’ve got your Python class ready to go, you need to actually get  your C# code to use it. The code below (with the exception of the actual call to the Python class) is relevant to the final implementation I’ll be demonstrating later, although the actual execution will change slightly. Nevertheless, if you’ve used an external Python class, here’s what you need to do:

  1. In your project, add references to the following DLLs, found in Iron Python’s installation directory (e.g. C:\Program Files (x86)\IronPython 2.6 for .NET 4.0):
    • IronPython.dll
    • IronPython.Modules.dll
    • IronPython.Dynamic.dll
    • Microsoft.Scripting.dll
    • Microsoft.Scripting.Debuging.dll
  2. Open Program.cs and add:
  3. In the Main method, create the Python engine object:
  4. Load the Python script file using the dynamic keyword. This will resolve the object’s operations at runtime:
  5. Create an instance of the Python Calculator class:
  6. Write some code to perform the desired calculations using the calc object.

The resulting program.cs file might look like this:

At this point, you can save, build and run the application. The .NET 4 executable performs the calculations by calling the calc object, which in turn resolves the result of the Calculator Python class, and performs our simple calculation:

1195-calc1.gif

Figure 1. The basic calculator.

While this method works perfectly well for basic calculations, I decided that it lacks elegance (and not a little functionality). So, in a moment, I will demonstrate how I did away with this external file altogether, fully encapsulated the python class within my C#, and executed it from within memory. However, before we go into that, I’ll illustrate how the basic interaction between C# and IronPython can flow in the opposite direction.

Calling C# Methods from Python

In the following example, I’ll perform the reverse operation; creating the calculator’s class in C# and then accessing it from Python. There is no attached demonstration for this, and it does not significantly inform the final build of the application, so this is primarily an academic exercise.

Create the C# Class

  1. In Visual Studio, create a new C# Class Library project with the name DynamicCS;
  2. Create a standard C# class in the DynamicCS project by renaming the existing Class1.cs class to Calculator.cs. Implement two simple methods for adding and subtracting numbers, as follows: The Calculator class is a valid C# class, but to access it as a dynamic object from Python, you need to have a wrapper class that inherits from DynamicObject, as demonstrated over the remaining steps:
  3. In the Solution Explorer, right-click the DynamicCS project file, and select Add > New Item > Class;
  4. In the Solution Explorer, rename the new file to DynamicCalc.cs;
  5. In the newly-created class, add:
  6. Define a public DynamicCalc class that derives from DynamicObject:
  7. Implement the constructor of the DynamicCalc class:
  8. Override methods from the DynamicObject class. In the presented example, the TryGetMember method has to be overridden, at the very least:
  9. The resulting DynamicCalc.cs file might look like this:

    Note that, in the TryGetMember method:

    • binder.Name represents a name of the method or property called;
    • result is an output value of the method or property. In this case, it is a delegate to the ‘add’ and ‘sub’ methods of the calc object;
    • return should return ‘true’ if the operation is successful, otherwise ‘false’.

Finally, save and build the solution. The Python executable performs the calculations by calling the calc object, which in turn resolves the result of the C# DynamicCalc class, imported from DynamicCS.dll.

Call the C# Methods from Python

  1. In the Solution Explorer, right click the DynamicCS project file, and select Add > New Item > Text file;
  2. In the Solution Explorer, rename the new file to client.py;
  3. Add an import sys statement, pointing to the directory where your C# DLL is located.  In this example, I have saved DynamicCS.dllin C:\MyProjects\DynamicCS\DynamicCS\bin\Debug:
  4. Reference your C# DLL:
  5. Create a Python object as you would for any other object, then use it to perform some calculations:
  6. The resulting client.py file might look like this:
  7. Save and run the Python client.

1195-calc3.gif

Figure 2. The basic calculator, implemented mostly in Python.Creating and calling Python methods in C#

The Python executable performs the calculations by calling the calc object, which in turn resolves the result of the C# DynamicCalc class, imported from DynamicCS.dll. The end result looks much the same as the earlier implementation.

Create the Python Class Directly in C# code

Working again with C# as the primary language, this is where things start to get a bit more interesting. Given that the python class is so simple and compact, I decided to use the dynamic keyword in a more creative way, and embed the python directly in the C# code:

  1. Start Visual Studio 2010 and create a new Console Application project with the name DynamicPyMem
  2. In your project, add references to the following DLLs, found in Iron Python’s installation directory (e.g. C:\Program Files (x86)\IronPython 2.6 for .NET 4.0):
    • IronPython.dll
    • IronPython.Modules.dll
    • Microsoft.Dynamic.dll
    • Microsoft.Scripting.dll
    • Microsoft.Scripting.Debugging.dll
  3. Open Program.cs and add:
  4. In the Main method, create the Python script as a string:
  5. In the Main method, create the Python engine and scope objects, and then execute the source:
  6. Create an instance of the Python Calculator class:
  7. Write some code to perform some calculations using the calc object:
  8. Save, build and run the application

So, having created this neat and smooth solution, the question is “What can we do with this?” For my part, I decided to bolt on a few bits and pieces, and turn the whole thing into a function plotter, rather than just a calculator. As an immediate result, the maths module changed somewhat, given that I now needed to evaluate expressions, rather than solve a single calculation. Thus, my Python engine now looks like this:

I don’t need to go into detail about the code behind the plotting functionality since you have the source code to look at. I’ve added components for calculating X and Y scales, and evaluating users’ expressions (entered as text) for about 500 values of X. In addition, the users may also supply parameters with which to populate their expression, which is significantly easier to deal with dynamically. Finally, the results of the evaluated functions are then plotted on a graph, meaning that I’ve also had to add this to the solution:

The Plot Thickens

As you’ll see when you try out the finished Plot Function application, that plotting happens remarkably quickly, illustrating just how efficient the use of Python is in this case. As a counterpoint, achieving the same evaluations of a user-supplied expression in pure C# is… cumbersome.

In the same way as in the earlier example, the .NET 4 executable performs the calculations by calling the calc object, which in turn resolves the result of the Calculator Python class. Python’s math module allows for the evaluation of very complex expressions; instead of the simple adding or subtracting of numbers, the program may calculate more complex mathematical expressions, such as 5*sin(pi/4)/(pi/4). Moreover, if the expression is defined as a function of x, it can have a general form, such as A*sin(x)/x (where A is a constant parameter), and it can then be evaluated for every value of x. Additionally, because the python program is just text, using it to create an intelligent expression evaluator is a neat example of applying python in C#.

Please feel free to download the attached example Plot function solution, which allows for the plotting of any function of x which is entered as text by the user (and which is acceptable by python) – i.e. the solution is not limited to a prefined set of functions. Take a look at the screenshot below for a quick demo of how to use it:

1195-plot.jpg

Figure 3. The function plotter and its controls

Final Thoughts

So, in this article, we’ve seen a simple way of how the ‘dynamic’ keyword in C# can be used to integrate .NET code with Python, as well as way of embedding the necessary python code directly in the C# code. This is just the result of a little tinkering I’ve done, but hopefully this will give you some ideas of how to draw on the benefits offered by other .NET  programming languages when most appropriate.