Programming with Boo

Boo Speak

© Piumadaquila, Fotolia

© Piumadaquila, Fotolia

Article from Issue 103/2009
Author(s):

Hooked on Python's "wrist-friendly" syntax? Enamored of .NET architecture but equally appreciative of C#'s strong typing? Boo offers the best of three worlds.

Unlike other development platforms, the .NET framework can mix and match code from any number of programming languages. For those who program in .NET, the universal code form known as Microsoft Intermediate Language (MSIL) is a lingua franca. If you can translate your source code into MSIL, you can combine it with, say, Visual BASIC.NET or C# to produce one executable.

Indeed, given such flexibility, developers have adapted many popular languages to .NET. IronPython [1] is a full implementation of Python for .NET, and IronRuby [2] is a proposed .NET-ready implementation of Ruby. Also, you can find Java, Lisp, and Smalltalk for .NET. Moreover, if you don't like any of the existing programming languages, you can create your own. If you can consume source code and produce MSIL, the sky is the limit.

In fact, that's the genesis of Boo [3]. Hooked on Python's sparse, "wrist-friendly" syntax but enamored of the .NET architecture and the strong typing found in C#, developer Rodrigo Barreto de Oliveira set out to combine the best features of both – with just the right amount of Ruby – into something readily suited to iterative development.

In this article, I help you get started with Boo and show you how to use the MonoDevelop IDE to write and test some Boo code [4] [5]. Boo is available through an MIT-style license, which provides broad latitude for using the code and creating derivative works.

Boo-dles of Good Ideas

The Boo Primer [6] is a well-written introduction to the Boo language. The constructs and syntax of each element are described in detail; you can also learn quite a bit by browsing the sample code provided with the Boo compiler and its test suites. As you study the Boo language, you will start to get a sense of how it works.

Boo offers both a list and an array type. A list can vary in size, and an array is fixed in size. You can use either a list or an array to extract one, some, or all elements, and both can contain heterogeneous elements. Listing 2 demonstrates some similarities and differences between a list and an array.

The code in Listing 2 produces the following:

[0, 1, 2, 3, 4]
['hello', 1, true, System.Object]
[10, 'hello']
[1, True]
(0, 1, 2, 3, 4)
(0, 1, 5, 3, 4)
(1, 5)

Both the list and array use brackets ([] ) for indexing and slicing; a list is displayed with brackets, and an array appears with parentheses to differentiate. A slice can be a single element or a bounded or unbounded range. m[1:3] includes the element at index 1 and everything up to but not including the third element. m[:2] is the set of all elements up to but not including the second to last. An out-of-bounds access in either a list or an array yields an exception.

Interestingly, a string behaves like a range and a list.

print (s = List('abcdefghi'))
[a, b, c, d, e, f, g, h, i]
print s[0:4]
[a, b, c, d]
print (s.Add('z'[0]))
[a, b, c, d, e, f, g, h, i, z]

Like Perl and Ruby, Boo also offers a hash to store (key, value) pairs.

A struct (short for structure) is like a class – a struct can have instance variables and methods, but it is stored as a value instead of a reference. A method is an object, too, and it has its own methods. Making each function its own object has practical uses. For example, you can instantly run a function in its own thread by calling the method's own BeginInvoke() method. You can terminate the thread by calling the function's EndInvoke() method.

Boo also provides a macro named lock to grant a thread mutually exclusive access to an object during an operation.

Other macros are provided, too, but the more compelling story is that anyone can create a new macro using any CLI language. Macros save typing, yes, but also reduce errors and compartmentalize sections of code. For example, a with macro can transform the wordy sequence:

fooInstanceWithReallyLongName = Foo()
fooInstanceWithReallyLongName.f1 = 100
fooInstanceWithReallyLongName.f2 = "abc"
fooInstanceWithReallyLongName.DoSomething()

… into the more succinct statement …

with fooInstanceWithReallyLongName:
 _f1 = 100
 _f2 = "abc"
 _DoSomething()

Boo has other nice features, but the macro, which allows the creation of domain-specific languages, might be its most powerful feature.

Listing 2

List and Array

01 l = List(range(5))
02 m = ['hello', 1, true, object]
03 n = []
04 n.Add(10)
05 n.Add('ten')
06 print l
07 print m
08 print n
09 print m[1:3]
10
11 a = array(range(5))
12 print a
13 a(2) = 5
14 print a
15 print a[1:3]

Python + Ruby + C# = Boo

Python has minimal syntax and uses white space to connote program structure. Boo follows suit. Listing 1 is a Boo program that reformats text lines to fit within a specific width.

The output of test("this is a very long string") is wrapped text with no more than 12 characters per line:

this is a*
*very long*
*string

As you can see from Listing 1, Boo is very spartan: no semicolons, no braces, no classes (if not needed), and no mandatory variable declarations. Just assign and go. But Boo is simple in form only. Type is enforced both implicitly and explicitly. Formal arguments can be typed, as you can see in the definition of the wrapLines() method. Otherwise, type is inferred.

Listing 1

Reformatting Text

01 import System.Text.RegularExpressions
02
03 def getWordBreaks(s as string):
04     return m.Index for m as Match in /\b|$/.Matches(s)
05
06 def wrapLines(s as string, columns as int):
07
08     lines = []
09
10     nextBreak = columns
11     lastBreak = 0
12     lineStart = 0
13     for wb as int in getWordBreaks(s):
14         if wb > nextBreak:
15             line = s[lineStart:lastBreak]
16             lines.Add(line.Trim())
17             lineStart = lastBreak
18             nextBreak = lastBreak + columns
19         lastBreak = wb
20
21     lines.Add(s[lineStart:].Trim())
22
23     return lines
24
25 def test(s):
26     print(join(wrapLines(s, 12), "*\n*"))

For example, the assignment lines = [] implies that lines is a list. Similarly, nextBreak = columns infers that nextBreak is an int.

Ruby infers type as well. As in Ruby, everything in Boo is an object. The following is an interesting snippet of code from the Boo Primer [6]. (Once you build the Boo interactive shell, as described later in this article, you can try this code yourself.)

o as object
o = '12'
o = 4

Because o is instantiated as an object, the subclass of all types, it can reference any other type. This canonical example demonstrates polymorphism. However, if you declare i more narrowly at the outset, Boo catches an errant assignment.

i as int
i = 4
i = '12'
a = '12'
--------
ERROR: Cannot convert 'string' to 'int'.

Ruby and Boo have another language feature in common: Both support duck typing, as in "If it walks like a duck and quacks like a duck, it must be a duck." Or more to the point, if an object looks like a string, acts like a string, and responds to the same methods that an object of type string responds to, then it must be either a string, or a clever enough mimic to pass as a string.

To use duck typing in Boo, use the eponymous type duck. Boo forgoes compile-time type checking on variables declared as a duck.

fudd as int
daffy as duck
fudd = 0
daffy = 1
daffy = "quack"
fudd = "be vewy quiet"
ERROR: Cannot convert 'string' to 'int'.

Typically, you only have to specify a type when it is to your advantage. For instance, Boo provides method overloading, an added benefit of declaring the type of arguments. Otherwise, do not declare a type; let inference do the heavy lifting.

# x in an int and can do math
x = 5
x += 5
# now, x is a string
x = 'hello'
print x.ToUpper()
'HELLO'

The most common of programming types have succinct, lowercase names, such as object, int, string, double, and bool. More complex types are capitalized, as in List or Match.

Booting Up Boo

To use Boo, you must install the MonoDevelop integrated development environment (IDE), a suite of coding tools designed for C# and other .NET languages. The latest version of MonoDevelop is 1.9.2, a pre-release of the forthcoming MonoDevelop 2.0. Binary packages of Mono and MonoDevelop are available for a variety of Linux distributions and other platforms, including Mac and Windows, or you can build the software from source.

To build from source, make sure your Linux machine has the typical suite of development tools required to build Gnome applications.

Some other utilities and development libraries are also required: a Java Runtime, the Bison parser generator, the pkg-config utility, the Pango rendering library, the ATK accessibility library, the Gtk 2.0 libraries, the Curses library, some CLI bindings, and the GNU Library (glib) version 2.0 or greater. For the necessary packages, check your distribution's package manager.

Next, download and unpack the tarballs for MonoDevelop and its dependencies. (See a comprehensive list of components on the Mono site [7].) Nine packages are required (Listing 3).

Listing 3

Setting Up MonoDevelop

01 # Make a workspace
02 $ mkdir $HOME/mono
03 $ cd $HOME/mono
04
05 $ # Download, unpack, and build all the source code   packages required
06 $ # Mono
07 $ wget http://ftp.novell.com/pub/mono/sources/mono/        mono-2.2.tar.bz2
08 $ tar xjf mono-2.2.tar.bz2
09 $ ( cd mono-2.2; ./configure; make; sudo make install )
10
11 $ # GDI+
12 $ wget http://ftp.novell.com/pub/mono/sources/libgdiplus/        libgdiplus-2.2.tar.bz2
13 $ tar xjf libgdiplus-2.2.tar.bz2
14 $ ( cd libgdiplus-2.2.; ./configure; make; sudo make    install )
15 $ # Tell the loader to look in /usr/local/lib for libraries
16 $ sudo echo '/usr/local/lib' >> /etc/ld.so.conf.d/win32.             conf
17 $ sudo ldconfig
18
19 $ # GTK#
20 $ wget http://ftp.novell.com/pub/mono/sources/        gtk-sharp212/gtk-sharp-2.12.7.tar.bz2
21 $ tar xjf gtk-sharp-2.12.7.tar.bz2
22 $ ( cd gtk-sharp-2.12.7; ./configure; make; sudo make    install )
23
24 $ # GNOME#
25 $ wget http://ftp.novell.com/pub/mono/sources/        gnome-sharp220/gnome-sharp-2.20.1.tar.bz2
26 $ tar xjf gnome-sharp-2.20.1.tar.bz2
27 $ ( cd gnome-sharp-2.20.1; ./configure; make; sudo make    install )
28
29 $ # Mono Tools
30 $ wget http://ftp.novell.com/pub/mono/sources/mono-addins/        mono-addins-0.4.zip
31 $ unzip mono-addins-0.4.zip
32 $ ( cd mono-addins-0.4; ./configure; make; sudo make    install )
33
34 $ # The MonoDevelop IDE
35 $ wget http://ftp.novell.com/pub/mono/sources/monodevelop/        monodevelop-1.9.2.tar.bz2
36 $ tar xjf monodevelop-1.9.2.tar.bz2
37 $ ( cd monodevelop-1.9.2; ./configure; make; sudo make    install )
38
39 $ # The Nant Build Tool
40 $ wget http://superb-east.dl.sourceforge.net/sourceforge/        nant/nant-0.86-beta1-src.tar.gz
41 $ tar xzf nant-0.86-beta1-src.tar.gz
42 $ (cd nant-0.86-beta1; make; sudo make install )
43
44 $ # The Mono Debugger
45 $ wget http://ftp.novell.com/pub/mono/sources/        mono-debugger/mono-debugger-2.2.tar.bz2
46 $ tar xzf mono-debugger-2.2.tar.bz2
47 $ ( cd mono-debugger-2.2; ./configure; make; sudo make    install )
48
49 $ # Support for the Mono Debugger in monodevelop
50 $ wget http://ftp.novell.com/pub/mono/sources/        monodevelop-debugger-mdb/\        monodevelop-debugger-mdb-1.9.2.tar.bz2
51 $ tar xjf monodevelop-debugger-mdb-1.9.2.tar.bz2
52 $ (cd monodevelop-debugger-mdb-1.9.2; make; make install )

Pay particular attention to the instructions for GDI+: You must configure the loader to pick up libraries in /usr/local/lib. If you attempt to run some of the Boo Windows Forms applications and get an error such as System.DllNotFoundException: gdiplus.dll, you skipped this step. (See the Mono project website for more information [8].)

A complete build takes about 30 minutes and yields the Mono engine, the nant build tool (similar in purpose to make), the MonoDevelop IDE, a debugger, and a panoply of Linux and .NET libraries. By default, all of the software is installed in /usr/local or its subdirectories. In each command, use ./configure --prefix directory_name to specify an alternate target, such as /opt/local.

The next step is to download and build the Boo compiler and the Boo environment for MonoDevelop:

$ wget http://dist.codehaus.org/boo/distributions/boo-0.9.0.3203-2-src.zip
$ mkdir boo; unzip ../boo-0.9.0.3203-2-src.zip

Before you continue, edit the file default.build and change the line <property name="skip.vs2005" value="False" /> to read <property name="skip.vs2005" value="True" />. This step skips the Visual Studio--specific portion of the Boo build. Now, compile Boo:

$ cd boo
$ /usr/local/bin/nant rebuild
$ /usr/local/bin/nant update-bin
$ /usr/local/bin/nant compile-tests && nunit-console tests/build/*Tests.dll
$ /usr/local/bin/nant install
$ cd ..

Now you have a complete working copy of the Boo compiler booc. To try it, build and execute one of the example Boo programs found in ./examples.

$ # Compile and run the code
$ booc examples/arrayperformance.boo
$ mono arrayperformance.exe
153.613 elapsed.
250.573 elapsed.
216.785 elapsed.
$ # Interpret the code
$ booi arrayperformance.boo
153.613 elapsed.
250.573 elapsed.
216.785 elapsed.

Success! The sample, arrayperformance.boo, copies a large array and benchmarks the elapsed time. Also, you can test Boo directly in the Boo interactive interpreter, booish (Listing 4).

Listing 4

Working with booish

01 Welcome to booish, an interpreter for the boo programming language.
02 Running boo 0.9.0.3203 in CLR v2.0.50727.1433.
03
04 Enter boo code in the prompt below (or type /help).
05 >>> print "Hello, world"
06 Hello, world

At long last, you are ready to add Boo support to MonoDevelop (see Listing 5). A link to scripts that build the software for you can be found at the Linux Magazine website [9].

Listing 5

Adding Boo

01 $ # The next two steps are required until the boo makefiles used in
02 $ # the previous step are fixed.
03 $ sudo mkdir -p /usr/local/lib/boo
04 $ sudo cp /usr/local/lib/mono/boo/*.dll /usr/local/lib/boo
05
06 $ wget http://ftp.novell.com/pub/mono/sources/monodevelop-boo/        monodevelop-boo-1.9.2.tar.bz2
07 $ tar xjf monodevelop-boo-1.9.2.tar.bz2
08 $ ( cd monodevelop-boo-1.9.2; ./configure; make; sudo make install )

Using MonoDevelop to Create Boo Programs

First, launch the MonoDevelop IDE with monodevelop. The main window resembles Figure 1. To create a Boo application, click on Start a New Solution, click Boo, and select Empty Project. Next, pick a name for the project and a location in which to store it and click OK. On the next screen, enable Unix Integration (optional) and click OK. Now you should have a solution in the list on the left.

Figure 1: The MonoDevelop main window.

Here, you need to choose the solution, right-click, and choose Add | New File…; next, choose Empty File and give the file a name, then click New. At this point, you are ready to edit Boo code in the main panel. The editor colors syntax as you type, and it automatically indents on the basis of context. And because you are in Mono, you can build on the .NET frameworks or any framework with a CLI binding, such as Gtk#.

Now enter the code in Listing 6 in MonoDevelop, save the file, and choose Run | Run.

Listing 6

Trying Out Boo Classes

01 import System.Windows.Forms from System.Windows.Forms
02 import System.Drawing from System.Drawing
03
04 class PropertyEditor(Form):
05     def constructor([required] obj):
06         grid = PropertyGrid(Dock: DockStyle.Fill,   SelectedObject: obj)
07         Controls.Add(grid)
08
09 class Options:
10     [property(Message)]
11     _message as string
12
13     [property(Font)]
14     _font as System.Drawing.Font
15
16 options = Options(Message: "Hello!", Font: Font("Lucida Console", 12.0))
17 editor = PropertyEditor(options)
18 editor.ShowDialog()
19 print(options.Message)

Listing 6 produces the output shown in Figure 2. This example also demonstrates Boo classes. The phrase class PropertyEditor(Form) defines the class PropertyEditor and derives it from the Windows Form's class Form. The constructor() method is self-evident. The statements [property(Message)] and _message as string create a setter and getter method named for the property _message, which is a Boo string. The [property(Font)] statement is similar, although it is a font.

Figure 2: Fonts and Boo –

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • Novell Releases Mono 2.6 and MonoDevelop 2.2

    The Mono framework compatible with Microsoft's C# .NET is available in version 2.6. Developers also upgraded its associated MonoDevelop environment to version 2.2.

  • Mono and DotGNU

    The Open Source projects Mono and DotGNU open Microsoft’s .NET platform to Linux developers. This article investigates how well-suited these alternative implementations are for building simple GUI applications.

  • MonoDevelop Soon for Moblin/MeeGo

    The integrated MonoDevelop environment will soon be available for developing and debugging applications for the MeeGo (alias Moblin/Maemo) mobile platform.

  • Mod_Mono

    Mod_Mono lets you host .NET applications on your Linux Apache 2 server.

  • DotGNU

    Write C# programs in Linux with the free and vendor-neutral DotGNU.

comments powered by Disqus

Direct Download

Read full article as PDF:

068-072_boo.pdf  (419.27 kB)

News

njobs Europe
What:
Where:
Country:
Njobs Netherlands Njobs Deutschland Njobs United Kingdom Njobs Italia Njobs France Njobs Espana Njobs Poland
Njobs Austria Njobs Denmark Njobs Belgium Njobs Czech Republic Njobs Mexico Njobs India Njobs Colombia