PerlNET is the new product released by ActiveState as part of their Perl Development Kit (PDK Version 4.1.1). PerlNET enables you to create and use .NET assemblies in Perl. The architecture of PerlNET is elegant, in that it makes it easy to wrap the existing Perl Modules and serve them to other .NET programs. PerlNET actually executes the Perl code using the standard Perl interpreter as "unmanaged code." First, I'll explore PerlNET with a simple console example, then move on to writing and using .NET components and how to wrap existing Perl Modules with PerlNET. Lastly, I'll conclude this article with discussions on programming Windows Forms in PerlNET.
Say Hello to PerlNET
Let us begin with a most familiar programming theme, the "Hello World!" example. Listing 7
shows the necessary code to say "Hello World!" using PerlNET.
The Perl reserved word use
in line 1 and 2 tells the Perl Interpreter/PerlNET Compiler to include .NET's System namespace. The qw (AUTOCALL) instructs the Perl Compiler to retry all the calls as .NET calls, for which no Perl method was found. Thus, if I remove line 2 in Listing 7
, I have to rewrite line 4 by using PerlNET::Call, which is the generic way of calling any .NET Static methods, otherwise called as Class methods.
PerlNET::Call("Console.WriteLine", "Long Hi!")
The Perl Development Kit provides plc.exe, a Perl compiler that compiles PerlNET code to .NET assemblies. The code in Listing 7
is compiled as follows:
plc --target=exe HelloWorld.pl
One pitfall with the PerlNET compiler is that it provides syntax checks for .NET types and methods only at runtime instead of compilation time! Therefore, if you had typed WriteLine
, you would know it only while running the program.
A Different Type of Animal
One of the proven ways to implement complex applications is to break the monolithic applications into reusable, integral software programs as components. Getting data across the components with correct data types is the crucial challenge in any component-based programming. The task of solving this is called Type Marshalling. In cases like PerlNET, this gets more challenging as it bridges between two different technologies: a loosely typed language and a strongly typed framework! And PerlNET could not have made it any easier. The following code snippet shows one of the ways to achieve type marshalling, which is by using a static method of Convert class:
$x = "50";
PerlNET also provides type conversion Perl functions to be used while passing parameters or returning values to .NET. The following table lists those functions.
|System Types||PerlNET Type|
|While interfacing with .NET, PerlNET uses special comment blocks called POD (Plain Old Documents) to define types.|
This works fine for converting method parameters, which is needed when writing simple, pure Perl programs that interact with .NET assemblies. But to write our own PerlNET components or extend .NET components, there is a need to specify the types at the definition level. While interfacing with .NET, PerlNET uses special comment blocks called POD (plain old documents) to define types. (See: POD in Perl
On the interface side, the important ones are: Methods, which perform actions; Properties, which are accessed via getter and setter methods; Fields, which are accessed directly without any methods; and Constructors, which create the objects. In terms of types, PerlNET supports three kinds of types: pure Perl, .NET and mixed. Let's see some examples of Pure Typed programs.
provides an example of building a pure typed, .NET component using PerlNET, and Listing 9
shows how to use it in a Perl program. These are compiled, respectively, as:
plc --target=library City.pm
csc /reference:City.dll CityClient.cs
|An easy way to design components in PerlNET is to design them as Perl modules.|
In reference to Listing 8
, the easy way to design components in PerlNET is to design them as Perl Modules. Perl Modules have an extension of ".pm". A Perl Module has some unique features. You use the package statement to define the namespace. A Perl Module is a reusable package that is defined in a file whose name is the same as the Package with a ".pm" appended. Perl implicitly passes the name of the package as a parameter to every subroutine defined within that package's namespace. Often this is gathered into a variable named as $self. You can see that in lines 35, 46 and 56 of the code.
In Lines 5 through 22, you see multiple =for interface statements. These are the POD statements through which PerlNET defines types of all the methods, constructors and attributesin general, all the interface elements. In our example, the constructor is defined in line 9. But I don't have a subroutine by that name. Why is that? This is because line 9 is there for interfacing purposes and Perl constructors are named as new and not in the name of the class. The new subroutine is defined in line 24. This subroutine creates the class with the help of the bless built-in, which attaches a given hash (in our case it is the $city) to the current class. This enables subsequent accesses to the member variables in terms of this blessed hash. Line 8 specifies to PerlNET that this is a pure Perl component.
|Pure typed PerlNET components cannot implement fields or virtual fields, and cannot inherit from a .NET type.|
Pure typed PerlNET components cannot implement fields or virtual methods. Also, they cannot inherit from a .NET type. For these reasons, I could create .NET type or mixed type components. An advantage of pure Perl components is that they can be used even with normal Perl programs, making it easy to wrap existing Perl Modules and Classes and create .NET component assemblies. (See: PerlNET: The Bridge between Perl and .NET
PerlNET implements the public, private and protected access modifiers also in terms of =for interface blocks. The following code snippet declares a property name as a private method:
private int name;
Next, let's see how to use a .NET component in Perl. Listing 10
shows an example Perl program that consumes the component created by Listing 8
Note that the usage of PerlNET::true in Listing 10
could be cut short by including true as:
use PerlNET qw (AUTOCALL true);
The code in Listing 10
should be compiled by referencing the City.dll that was created before:
plc -reference=City.dll CityPerlClient.pl