Concurrent Ada Programming

Ada’s model for doing concurrent programming is absolutely marvelous, and today I’m going to give you a small taste of it. More or less all programming languages provide tools for concurrent programming, but few do it as elegant as Ada, where the whole concept has been build into the language from it’s inception in 1983.

In Ada concurrent programming is a first class citizen, not an afterthought, and in this day and age where even the cheapest of processors have multiple cores, being able to properly harness the power of those many cores is important. A lot of programs could benefit from a bit of concurrent magic, but since concurrent programming brings with it a whole new set of problems, many programmers shy away from it. Not so with Ada programmers. We have tasks, protected objects, scheduling, guards and entries right there in front of us. In this article I’m going to show you how tasks and protected objects can be used to add concurrency to a very simple program.

The first thing we’re going to do is setup a small program that solves the plain problem of counting 20 times to 1_000_000_000.

One possible Ada solution to this problem is this:

with Ada.Task_Identification;
with Ada.Text_IO;
 
procedure Sequential
is
   use Ada.Task_Identification;
   use Ada.Text_IO;
 
   Id   : constant String := Image (Current_Task);
   Jobs : Positive := 20;
begin
   for Job in reverse 1 .. Jobs loop
      for K in 1 .. 1_000_000_000 loop
	 null; --  This is really hard!
      end loop;
 
      Put_Line ("Job" & Positive'Image (Job) & " done by " & Id);
   end loop;
end Sequential;

Before we get into actually compiling and running Sequential, allow me to first explain what’s going on in the program.

First we with the two packages Ada.Task_Identification and Ada.Text_IO. What this does is make the subprograms and types from those packages visible and available to our program, somewhat analogous to the #include directive used in C. After that we setup our “main” procedure and name it Sequential. In Ada you can call your main procedure whatever you like. The use clauses we encounter next lets us access the tools of the Ada.Text_IO and Ada.Task_Identification packages without having to prefix every type and subprogram with the package name. This is equivalent to the using namespace statement in C++.

The Ada.Task_Identification package makes it possible for us to figure out the id of a running task and Ada.Text_IO makes the Put_Line procedure available to Sequential.

We declare and initialize two objects in the declarative part of the program (between is and begin): Id and Jobs. The Id constant contains a String representation of the environment task identifier. As our program only have one running task (or thread if you will), which is the main environment task, the output done in the Put_Line line will show the same Id for every job completed.

The Jobs variable is the queue of jobs, in our case 20. Note that the Positive type is actually a subtype of Integer with the range 1 .. Integer'Last. If you try to assign a value below 1 or above Integer'Last then the program will raise a Constraint_Error exception.

After the begin keyword we’re in the actual body of the program, and the first thing we do is setup a for loop that’ll count down from 20 to 1, as indicated by the reverse keyword and the given range of 1 .. Jobs.

Inside this loop we do the actual work: Counting to 1_000_000_000 for each job and then outputting a line of text indicating whenever a job has been completed and by which task id.

And that’s it.

In order to compile the program do:

gnatmake sequential.adb

And then to execute and time:

time sequential

My laptop yields the following when executed and timed:

thomas@t420:~/Ada/Simple_Tasking time sequential
Job 20 done by main_task_000000000064A010
Job 19 done by main_task_000000000064A010
Job 18 done by main_task_000000000064A010
Job 17 done by main_task_000000000064A010
Job 16 done by main_task_000000000064A010
Job 15 done by main_task_000000000064A010
Job 14 done by main_task_000000000064A010
Job 13 done by main_task_000000000064A010
Job 12 done by main_task_000000000064A010
Job 11 done by main_task_000000000064A010
Job 10 done by main_task_000000000064A010
Job 9 done by main_task_000000000064A010
Job 8 done by main_task_000000000064A010
Job 7 done by main_task_000000000064A010
Job 6 done by main_task_000000000064A010
Job 5 done by main_task_000000000064A010
Job 4 done by main_task_000000000064A010
Job 3 done by main_task_000000000064A010
Job 2 done by main_task_000000000064A010
Job 1 done by main_task_000000000064A010

real    0m52.737s
user    0m52.636s
sys     0m0.001s

As you can see it took a good 52 seconds to finish all 20 jobs. At no point during the execution of the program did the system utilize more than one CPU core. Each job was completed in an absolute sequential manner, starting with job 20 and ending with 1.

Surely this is sad, considering my laptop is equipped with a CPU sporting a whooping four cores. Lets add some tasking magic to the program and see how much faster we can make it go.

with Ada.Task_Identification;
With Ada.Text_IO;
 
procedure Concurrent
is
   use Ada.Task_Identification;
   use Ada.Text_IO;
 
   protected Jobs is
      procedure Get 
	(Job : out Natural);
   private
      J : Natural := 20;
   end Jobs;
 
   ------------
   --  Jobs  --
   ------------
 
   protected body Jobs is
      -----------
      --  Get  --
      -----------
 
      procedure Get 
	(Job : out Natural)
      is
      begin
	 Job := J;
         if J > 0 then
            J := J - 1;
         end if;
      end Get;
   end Jobs;
 
   task type Worker;
   --  The Worker gets a job, and does the hard work.
   --  When there are no more jobs, the Worker exits.
 
   --------------
   --  Worker  --
   --------------
 
   task body Worker is
      A_Job : Natural;
      Id    : constant String := Image (Current_Task);
   begin
      loop
	 Jobs.Get (A_Job);
 
	 exit when A_Job < 1; 
 
	 for K in 1 .. 1_000_000_000 loop
	    null; --  This is really hard!
	 end loop;
 
	 Put_Line ("Job" & Natural'Image (A_Job) & " done by " & Id);
      end loop;
   end Worker;
 
   Workers : array (1 .. 4) of Worker;
begin
   null; --  We're not using the main environment task for anything.
end Concurrent;

Let’s dive in!

We with and use the same packages as before, but after that there are quite a few new things, first of which is a protected object. In Ada these are objects that export procedures, functions and entries that enables us to interact with the encapsulated data structure. In our case we’ve setup a protected object called Jobs, but we could just as well have created a protected type and then declared one of more objects to be of that type.

We can only operate on the data structure of a protected object via the exported subprograms and this is done under automatic mutual exclusion. A protected object will allow many concurrent readers (via exported functions), but only one writer (via exported procedures and entries).

A protected object is just what we need to protect our job queue from race conditions, now that we have several tasks querying and updating it.

   protected Jobs is
      procedure Get 
	(Job : out Natural);
   private
      J : Natural := 20;
   end Jobs;
 
   ------------
   --  Jobs  --
   ------------
 
   protected body Jobs is
      -----------
      --  Get  --
      -----------
 
      procedure Get 
	(Job : out Natural)
      is
      begin
	 Job := J;
         if J > 0 then
            J := J - 1;
         end if;
      end Get;
   end Jobs;

First we declare our Jobs protected object. We export the sole Get (Job : out Natural) procedure, which is the only way for us to interact with the very simple data structure, consisting only of the variable J.

In the body of Jobs we find the actual implementation of the Get procedure. All it does is put the current value of J into the Job parameter and then decrease the value of J by one. With this simple system in place we’re ensured that access to J is only ever granted to one single task at the same time. Only when that task is done is the next one allowed access.

With a secure job queue in place we move on to creating the tasks that will be doing the actual work:

   task type Worker;
   --  The Worker gets a job, and does the hard work.
   --  When there are no more jobs, the Worker exits.
 
   --------------
   --  Worker  --
   --------------
 
   task body Worker is
      A_Job : Natural;
      Id    : constant String := Image (Current_Task);
   begin
      loop
	 Jobs.Get (A_Job);
 
	 exit when A_Job < 1; 
 
	 for K in 1 .. 1_000_000_000 loop
	    null; --  This is really hard!
	 end loop;
 
	 Put_Line ("Job" & Natural'Image (A_Job) & " done by " & Id);
      end loop;
   end Worker;

First we declare a task type called Worker. We could’ve setup a task object, just as we did with the Jobs protected object, but since we want more than one worker a type is the way to go. The body of the task looks a lot like the body from the Sequential program, with a few minor differences. We declare the A_Job variable to be of the type Natural, which is a subtype of Integer with the range 0 .. Integer'Last. The Id constant is exactly like the one from the first program.

In the body of the Worker task we’ve got a plain loop that starts out with putting a job into the A_Job variable. We then check if the job is valid in the exit when... line and if not we exit the loop and the task is then completed.

The for loop and the Put_Line code is more or less the same as before.

Last we have this:

   Workers : array (1 .. 4) of Worker;
begin
   null; --  We're not using the main environment task for anything.
end Concurrent;

Here we declare an array of 4 Worker tasks. As soon as the program reach this spot, four workers are created and when we pass begin they spring to life. Since we already have 4 workers counting to 1_000_000_000 like there’s no tomorrow, we don’t really need to add any code to the main environment task, so we simply add a null statement. The main environment task is the master of the 4 workers, so it wont complete until all 4 workers have completed.

Lets see how the program performs now:

thomas@t420:~/Ada/Simple_Tasking$ time concurrent
Job 20 done by workers(4)_000000000065FCC0
Job 19 done by workers(2)_0000000000659240
Job 18 done by workers(3)_000000000065C780
Job 17 done by workers(1)_0000000000655D00
Job 16 done by workers(4)_000000000065FCC0
Job 15 done by workers(2)_0000000000659240
Job 13 done by workers(1)_0000000000655D00
Job 14 done by workers(3)_000000000065C780
Job 12 done by workers(4)_000000000065FCC0
Job 10 done by workers(1)_0000000000655D00
Job 11 done by workers(2)_0000000000659240
Job 9 done by workers(3)_000000000065C780
Job 6 done by workers(2)_0000000000659240
Job 8 done by workers(4)_000000000065FCC0
Job 7 done by workers(1)_0000000000655D00
Job 5 done by workers(3)_000000000065C780
Job 4 done by workers(2)_0000000000659240
Job 3 done by workers(4)_000000000065FCC0
Job 1 done by workers(3)_000000000065C780
Job 2 done by workers(1)_0000000000655D00

real    0m18.727s
user    1m11.454s
sys     0m0.025s

YAY! It is much faster now, and all four cores on my CPU is running at 100% while the program executes. Also note how the jobs are no longer completed sequentially. You can experiment with the amount of workers by changing the size of the Workers array. On my box the sweet spot is firing up 20 workers at the same time. With twenty workers I’m very close to a clean 18 seconds. The second fastes result is obtained with 4 workers. Every other amount of workers I’ve tried is slower.

There’s of course a whole lot more to Ada and concurrent programming than shown here. This little example has barely scratched the surface. A good place to start is the Ada Programming Wikibook.

You can grab the code for these examples at github.com/ThomasLocke/Simple_Tasking.

Adding concurrency to an Ada program is very simple, and the model for doing it is both easy to understand and to work with. When you’re using Ada there’s simply no excuse for not adding concurrency to your program where it will benefit from it.

My xmonad (wm) config

Because I got inspired by h2′s my awesome (wm) config post, I thought I’d share my xmonad config.

xmonad is a tiling window manager based on Haskell and as you can see in the example, the configuration file is written in plain Haskell, and if you haven’t been subjected to a functional programming language before, it might look a bit alien, but don’t let that scare you off – it’s a great language and xmonad is a great window manager. Both are well worth the effort.

I personally use xmonad as the primary wm for my workstation and my laptop, both of which are powered by Slackware64 -current. It just works. Give xmonad a whirl, and enjoy the power of a really cool tiling window manager.

Functional Comprehension

I’m currently reading (and thoroughly enjoying!) a fantastic book called Learn you a Haskell for great good. The author is Miran Lipovača, and I gotta say that he’s one of the most entertaining writers I’ve ever come across. If you like programming, then get this book. It’s worth every cent. Oh, and because Miran is such a nice guy, you can read the book for free on the website. Awesome. But please don’t let that deter you from actually buying it. We want him to write more books like this, and people gotta eat you know.

I started reading this book because I wanted to dip my toes in the hot waters of functional programming, and Haskell appealed to me, primarily because I’ve wanted to start using the xmonad tiling window manager on my Slackware box. I came at Haskell with a very imperative mindset, knowing little to nothing about functional programming. I had some vague ideas about what I was getting into, but for the most part I believed it to be a matter of learning a new syntax.

Boy was I wrong.

Obviously you have to learn a new syntax, but you also have to learn to think in a completely new way. And to be honest, I’m finding it pretty darn hard, in a very pleasurable way. Haskell is nothing like anything else I’ve ever encountered. Let me give you an example. Early in the book the concept of list comprehensions are introduced, and alongside these a cute little task:

Which right triangle that has integers for all sides and all sides equal to or smaller than 10 has a perimeter of 24?

While this task is by no means rocket science, it does require a bit of effort to solve in a typical imperative language, and you’d probably end up with some less than pretty nested loops, perhaps something like this:

with Ada.Text_IO;
 
procedure Triangle is
   use Ada.Text_IO;
 
   Max_Length : constant Positive := 10;
   Perimeter  : constant Positive := 24;
begin
   for A in 1 .. Max_Length loop
      for B in A + 1 .. Max_Length loop
         for C in B + 1 .. Max_Length loop
            if (A*A) + (B*B) = C*C and then A+B+C = 24 then
               Put (A'Img & B'Img & C'Img);
            end if;
         end loop;
      end loop;
   end loop;
end Triangle;

Yea I know – not pretty, but there it is and the result when running this little marvel is

6 8 10

as expected.

Now lets see the Haskell way:

[(a,b,c) | c<-[1..10], b<-[1..c], a<-[1..b], a^2+b^2==c^2, a+b+c==24]

Simply enter the above in ghci (Haskell interactive mode), and you’ll get

[(6,8,10)]

Solved using one line. How awesome is that? And it’s very readable to boot! The three lists feed into the (a,b,c) triple according to the two predicates a^2+b^2==c^2 and a+b+c==24. And that’s it! Lets try and remove the last predicate

[(a,b,c) | c<-[1..10], b<-[1..c], a<-[1..b], a^2+b^2==c^2]

and see what we get:

[(3,4,5),(6,8,10)]

Those two triangles are the only Pythagorean triples within the range of 1..10. Very neat.

If you’re up for some fun, I can highly recommend taking a look at Haskell. It’s a language that appears to be jam-packed with all sorts of great/cool features and as if that wasn’t enough, you also get to use words like monads, zippers, monoids and functors. Get your Haskell groove on here.

Why I Love Free and Open Source Software

My love for, and interest in, Free and Open Source software comes from two fairly different perspectives. One perspective is that of me as a programmer, a geek and a freedom loving individual. Another, equally important, perspective is me as a businessman and entrepreneur.

The Geeky Me

I love Free and Open Source software, because it sets people free and enables them to tinker and learn. I hate black boxes with a passion, because they keep us from expanding our horizons, and they enable power monopolies to control the free flow of knowledge and information. The whole concept of keeping knowledge hidden is alien to me – it only benefits the few, where an open world benefit the many.

There’s also the complicated matter of who to trust? Can we really trust software that wont let us see what it is doing with our data? In this day and age, where everybody is connected to everybody, should we, as consumers of software, accept that we have no clue what our data is being used to? Of course not. Free and Open Source software enables us, the users, to confirm that no evil is being done with our data. I’d much rather trust an army of Open Source programmers over big business and government. Any day.

A free society requires Free and Open Source software. The only thing that has historically set people free, is knowledge. Today technology play a key role in making sure people all over the world can gain knowledge. Free and Open Source software is at the heart of this.

So the main attractions of Free and Open Source software to me as a geek, programmer and human being is that it’s a whole lot more trustworthy. It allows knowledge to be shared and it guarantees freedom for both developers and users alike. Free and Open Source software is at the very core of a free society and it is the spear with which ordinary people can destroy power monopolies. And there are still many power monopolies that needs to be completely eradicated from the face of our planet.

We will have our freedom.

The Entrepreneurial Me

From the perspective of a businessman (going on +20 years), the concept of Free and Open Source software is great primarily because of one thing: It enables me to take and maintain control of my business.

I have first hand experience with proprietary products and the companies that develop them. Since 1995 my business have suffered two serious setbacks solely because of proprietary software.

The first time was in 1999 where a vendor claimed I had to invest in a new software package, or my systems would fail due to Y2K issues. The new software would cost me $40K. I moaned and complained about this, as I had already bought and paid for the previous version of this software, only 2 years earlier. But the vendor was adamant: I had to buy the new package. And so I did. My entire business depended on this software, so I really had no choice. To this day I’m not at all convinced that the software even needed the upgrade, because the vendor not only installed the new package, they also completely removed the old hard drives from the server. I had no way of verifying that I actually needed the “upgrade”. The vendor took control of my company and my money. They literally had me by the balls.

The second time was in 2009 where I was suddenly told by a vendor, that they would no longer support and develop the software I had bought from them, despite the fact that I had paid almost $100K in license fees over the years. They just pulled the plug. No development has been done since, and in the summer of 2011 the vendor went bankrupt.

So now I’m stuck with a dead platform, that only works on Windows (ARGH!), and for which no further development and bug/security fixes are done.

Wonderful.

Had these critical pieces of software been Free and Open Source, I could’ve hired programmers of my own and kept the software viable. Had the software been Free and Open Source, chances are there would’ve been other vendors in the market. But alas it wasn’t (and isn’t) Free and Open Source, so now the software will go to it’s grave alongside the dead vendor.

I’ve learned an important lesson from these experiences: Never ever trust companies that aren’t willing to open source their product. If the product is closed source, run for the hills. If your business depends on software, as mine does, you better make sure it’s Free and Open Source.

Do. Not. Trust. Companies. That. Only. Deliver. Closed. Products.

Sooner or later they will f*ck you up.

Just as you would never build a house on a foundation you don’t know anything about, you should never build a business around software that is a black box, and over which you have zero control, because if you have zero control, then that means strangers potentially have 100% control – over YOUR business. That is not good. Trust me, I’ve lived through it.

So even if you don’t buy into the Free and Open Source software ideology in general, you should still only ever base a business on Free and Open Source software, simply because it is the only sane thing to do. Free and Open Source software enables you to run your business how you envision it, not how random vendor X decides. That alone is worth a lot. And “worth a lot” is sweet music to any businessman.

If you’d like to help make the world a better place, then consider joining one of the FSF’s: Free Software Foundation or Free Software Foundation Europe. I’m a member of the latter, as the URL of this blog might already have given away.

Ada Programming on Slackware

Over the past few months, I’ve received a whooping 4 requests for an article about how to install some basic Ada packages on a Linux system, and since 4 is a high number in my world, I decided I’d best get cracking on it.

And so I did.

Now we all know that Linux system is a very broad term, what with the abundance of versions available, but to me there’s really only one that counts, and that is Slackware, so that’s what I’m going to base this article on. Also I’m guessing that all you Debian, Red Hat and openSUSE folks already have much of this software readily available in your fancy package repositories. At least I know that there’s an Ada Policy for Debian, which usually equals some packages also.

We’ll be installing 5 Ada packages on a Slackware64 13.37 box. The 5 packages are:

All of these can be found at the libre.adacore.com website. We’ll be working with a full install of Slackware, with PostgreSQL and TeX Live added to the default Slackware packages. Also a regular user named thomas has been created. Only the compiler will be installed as root, the rest of the libraries will be installed as thomas. Obviously you should substitute all references to thomas according to your own setup.

This article will not deal with how to install Slackware, nor how to obtain the above Ada packages from libre.adacore.com.

Movies You Say?

When I decided to write this article, I also decided I wanted to do 5 short videos to accompany it. “Why?” you might ask, and that would of course be a completely valid question. The answer is simple:

Because it’s fun!

Also these 5 videos grant me the opportunity to get the phrase “Ada programming” on YouTube. Whether or not that actually help Ada’s search rank is yet to be seen, but it properly wont make it any worse. I hope.

Please bear in mind that I know zero about making videos, English is not my first language, and I’ve not done anything like this before. These videos are at best an amateurs feeble attempts at making something useful. One thing they do document, despite their less than stellar quality, is the fact that the commands you’ll read in this article actually works in real life.

Each video will be linked in the headline for the appropriate section below.

The Commands

Those of you who really can’t be bothered with videos will of course not be left behind. All the commands necessary to compile and install these Ada tools are made available in this article. Basically what you’re getting is my Bash history, with one little addition: Whenever I type something in a program such as an installer or in emacs, the typed text is indented 4 spaces, like this:

$ emacs somefile
    Stuff added to somefile
$ ./installer
    RETURN

In the first example some stuff is added to somefile using emacs, and in the second example RETURN is clicked while running the installer program. I hope this makes sense. Else watch the videos, as you’ll be able to see exactly what’s going on. Hey, I’m already getting pretty good at shamelessly plugging my own videos! I’m SEO personified. Or not.

Also when you see the year 2011 in file names and commands, you should of course substitute it with whatever edition you might’ve downloaded, be it newer or older. The same goes for obvious version numbers, such as 4.1 for XML/Ada.

Lets get to it..

Ada Programming on Slackware – Part 1: The GNAT GPL Compiler

Even though Slackware64 13.37 comes equipped with an Ada compiler out of the box, it’s really a rather old one and it’s not very suited as compiler for any remotely new Ada projects, and I know for a fact that it simply cannot compile AWS, so the first step is getting a new compiler on the system. My choice is the GNAT GPL compiler from AdaCore.

This is the file I’ve downloaded:

gnat-gpl-2011-x86_64-pc-linux-gnu-bin.tar.gz

As root do:

$ tar zxvf gnat-gpl-2011-x86_64-pc-linux-gnu-bin.tar.gz
$ cd gnat-2011-x86_64-pc-linux-gnu-bin/
$ ./doinstall
    RETURN
    RETURN
    Y
    Y
$ cd
$ emacs .bashrc
 
    PATH=/usr/gnat/bin:$PATH
    export PATH
 
    GPR_PROJECT_PATH=/usr/gnat/lib/gnat
    export GPR_PROJECT_PATH
 
    ADA_PROJECT_PATH=/usr/gnat/lib/gnat
    export ADA_PROJECT_PATH
$ source .bashrc
$ chown -R thomas:users /usr/gnat

Now, you can either re-type the .bashrc stuff into the /home/thomas/.bashrc file, or you can use this little trick:

$ tail -n 9 .bashrc >> /home/thomas/.bashrc

That simply moves the last 9 lines from the /root/.bashrc to /home/thomas/.bashrc. Quite nifty eh’? You must of course adjust the 9 to suit your needs. It should be less if you haven’t added the same amount of line breaks as I have.

Note that the Slackware system does not come with .bashrc setup by default, so you’re going to have to create it yourself, if haven’t already, and then source it manually. Or you can create a .bash_profile file to have it source automatically on login:

if [ -f ~/.bashrc ]; then
   . ~/.bashrc;
fi

And with that you now have a brand spanking new Ada compiler in /usr/gnat/ on your Slackware box:

$ gnatmake --version
GNATMAKE GPL 2011 (20110419)
Copyright (C) 1995-2011, Free Software Foundation, Inc.
...

Awesome eh?

Ada Programming on Slackware – Part 2: The Florist POSIX Library

Compiling and installing Florist is about as easy as it can get. This is the file I’ve downloaded and placed in /home/thomas:

florist-gpl-2011-src.tgz

As root do:

$ su - thomas
$ tar zxvf florist-gpl-2011-src.tgz
$ cd florist-gpl-2011-src
$ ./configure --prefix=/usr/gnat/
$ make -j 4
$ make install
$ cd

There are no tests nor demos available in the Florist source package, so the only way to test it, is to start using it. Simply add with florist; to your project file, and get cracking.

Ada Programming on Slackware – Part 3: The XML/Ada Library

If you’re looking for a deep and intensive challenge, then this section is not going to please you: XML/Ada is dead-simple to compile and install.

This is the file I’ve downloaded:

xmlada-gpl-4.1-src.tgz

As thomas do:

$ tar zxvf xmlada-gpl-4.1-src.tgz
$ cd xmlada-4.1-src/
$ ./configure --prefix=/usr/gnat
$ PROCESSORS=4 make all
$ make docs
$ make install
$ make test
$ cd dom/test
$ ./tostring
$ cd

With the GPR_PROJECT_PATH environment variable in place, all you have to do to use XML/Ada is with the necessary packages in your program, for example with DOM.Core.Documents; or with Sax.Readers;.

Ada Programming on Slackware – Part 4: The GNATcoll Library

GNATcoll is the first of these libraries where you actually have to make some decisions. It’s possible to enable/disable various components in GNATcoll, for example if you don’t ever plan on using the facilities to handle project files or SQLite databases, then you can disable them in the configure step. Use ./configure –help to see your options.

This is the file I’ve downloaded:

gnatcoll-gpl-2011-src.tgz

As thomas do:

$ tar zxvf gnatcoll-gpl-2011-src.tgz
$ ./configure --prefix=/usr/gnat/ --disable-projects --disable-pygtk
$ PROCESSORS=4 make
$ make install
$ cd examples
$ make
$ cd gmp/
$ ./isprime
    (try a few numbers)
$ cd

Usage is as usual: with gnatcoll; or with gnatcoll_postgresql or, well, you get the point.

So far so good. 4 down, only one to go.

Ada Programming on Slackware – Part 5: The Ada Web Server (AWS) Library

Last, but not least: The Ada Web Server. A marvelous piece of software that enables you to add HTTP(S) functionality to your Ada programs. And luckily it’s just as easy to compile and install as all the other libraries.

This is the file I’ve downloaded:

aws-gpl-2.10.0-src.tgz

As thomas do:

$ tar zxvf aws-gpl-2.10.0-src.tgz
$ cd aws-gpl-2.10.0-src
$ make setup
$ emacs makefile.setup
    LDAP=true
    PROCESSORS=4
$ make build
$ make build_doc
$ make install
$ cd demos/test_ldap
$ make
$ ./test_ldap

Note the missing ./configure step. Instead of that you edit the makefile.setup file to enable/disable various components and to define where AWS is installed.

With’ing aws in your project file is all you have to do to make use of its powerful facilities. Be sure to check the documentation, as there’s a lot of very interesting stuff in there.

One Final Note

In the above we’ve installed the latest official versions of the software (as per the time of writing), but that might not be the best solution. Actually I’ll go as far as to say that it isn’t the best solution, since AdaCore only release once each year. What I usually do is opt for the developer versions. There are usually fewer bugs in them, and you get to try some of the new stuff the AdaCore wizards are working on.

So, where might you find these fabled developer versions? Here of course:

I haven’t been able to track down a dev repo for Florist, and so far I’ve never had any need to upgrade GNAT GPL more than once a year.

I hope you’ve enjoyed this little ride through Ada land, and as usual: If you find any errors in my scribblings, please let me know.

Deleting remote tags with Git

I really like Git. It is an awesome tool, and since it’s also the VCS that got me into managing my source code (and other stuff), I’ve never really felt it was that hard to learn.

But then the other day I suddenly needed to delete a remote tag.

Deleting tags locally is dead simple:

$ git tag -d some_tag

There. Simple, logical and straightforward. Deleting tags on a remote on the other hand, is a bit more “confusing”, first and foremost because you’re not going to be using the git tag command at all. Instead you’ll be using git push.

Yea, that makes a lot of sense to me. It might make perfect sense to a hardcore Git user, but to someone like me it feels a bit “meh”.

In the manual for git push we find this little gem:

git push origin :experimental
Find a ref that matches experimental in the origin repository (e.g. refs/heads/experimental), and delete it.

Aha! Since our tag is “a ref” all we apparently have to do is push nothing to the ref, and Git will delete the ref on the remote. YAY! So in order to delete some_tag, we do:

$ git push origin :some_tag

And I can report that it does indeed work. The tag is removed from the remote, and all is well. I can’t say I really like this method. I would have much preferred that remote tags were deleted using the git tag command, perhaps by adding a –remote option or something like that, but hey, what do I know.

At least now I’ve learned that in order to delete remote tags, I need to push nothing over the wire. No delete options or delete commands. Just pure and utter emptiness. I’ve learned my lesson.

Ada with a side of JSON

So, you’ve got Ada and you need to handle some JSON data, but you’re not quite sure if there are tools available, or if you’re going to have to come up with a homegrown solution. Well, as luck will have it, you need look no further than to the excellent GNATColl library from libre.adacore.com:

The GNAT Component Collection is a suite of reusable software components and utilities. It has been used by AdaCore in developing the GNAT tool set, the GPS Integrated Development Environment, and GNAT Tracker, its web-based customer support interface.

There’s a lot of really nice stuff in GNATColl, but today I’ll focus on the very new and shiny JSON features. Actually, at the time of writing, the GNATColl JSON facilities are so new that they haven’t even made it into the GNATColl manual yet, but that’s not really a problem, since they are so very easy to grasp.

But before we can get cracking on the actual Ada code, we need to install GNATColl. My personal preference is to go with the latest development snapshot:

svn co http://svn.eu.adacore.com/anonsvn/Dev/trunk/gps/gnatlib/
cd gnatlib/
./configure ....
make
make install

Obviously you should take a look at the configure options, so you don’t end up trying to compile features you don’t want/need. Also it’s worth noting that if you want to be sure of success, then it’s probably best to use the GNAT GPL compiler from AdaCore. Once you’ve made it work with that, you can start experimenting with the FSF GCC compiler. I’ve compiled GNATColl with GCC 4.6.2, so I can at least attest to the fact that GNATColl compiled with that specific version at the time of writing.

So, now that we have GNATColl available, lets get down and dirty with some JSON.

Step one is to initialize an empty JSON_Value variable:

with Ada.Text_IO;
with GNATCOLL.JSON;
 
procedure JSON_Fun is
   use Ada.Text_IO;
   use GNATCOLL.JSON;
 
   Penguin : constant JSON_Value := Create_Object;
begin
   if Kind (Penguin) = JSON_Object_Type then
      Put_Line ("Yes, Penguin is a JSON object");
   end if;
end JSON_Fun;

Running that should give you this output:

Yes, Penguin is a JSON object

The Create_Object call is where the magic is at. This gives us an empty JSON object, to which we can add values using the Set_Field procedure. The Kind function returns the kind of JSON_Value we’re dealing with. There are 7 kinds:

type JSON_Value_Type is
     (JSON_Null_Type,
      JSON_Boolean_Type,
      JSON_Int_Type,
      JSON_Float_Type,
      JSON_String_Type,
      JSON_Array_Type,
      JSON_Object_Type);

It should be obvious what kinds of data the different types contain.

So, currently we’ve got an empty Penguin JSON object, next step is naming the cute little fellow. Add this to the JSON_Fun program:

Set_Field (Val        => Penguin,
           Field_Name => "name",
           Field      => "Linux");
 
if Has_Field (Penguin, "name") then
   Put_Line ("Our Penguin is named " & Get (Penguin, "name"));
end if;

And voila! We’ve got a penguin named Linux. Amazing stuff eh? In the above snippet we encounter two key subprograms in the GNATCOLL.JSON package: Set_Field and Get. The former adds data to a JSON_Value object, while the latter retrieves data. There are Set_Field and Get subprograms for all the available JSON_Value_Type's.

Moving on, lets give our penguin some parents. As we all know, Linux got a lot of parents, but we’ll settle on adding three of those to a JSON_Array:

   ...
   Parents : JSON_Array;
begin
   ...
   Append (Arr => Parents,
           Val => Create ("Linus Torvalds"));
   Append (Arr => Parents,
           Val => Create ("Alan Cox"));
   Append (Arr => Parents,
           Val => Create ("Greg Kroah-Hartman"));
 
   Set_Field (Val        => Penguin,
              Field_Name => "parents",
              Field      => Parents);
 
   Put_Line ("Linux got" 
             & Natural'Image (Length (Parents)) 
             & " parents.");
 
   Put_Line ("They are:");
   for J in 1 ..  Length (Parents) loop
      Put_Line (" " & Get (Get (Parents, J)));
   end loop;

Woah! Lots of new stuff going on here. Lets take it from the top. First we declare a new JSON_Array object: Parents. We then append JSON_Value objects to Parents using the Append procedure, which takes a JSON_Array as its first parameter and a JSON_Value as its second. If you’ve programmed for more than 2 weeks, you should already have guessed that the value of the second parameter is appended to the JSON_Array given as the first parameter. There’s an alternative method: Using the “&” function. It’s slower, but to some the code is more readable:

Parents := Parents & Create ("Linus Torvalds");

I personally like the Append approach, but you can use whatever floats your boat. Naturally you can append both JSON_Value's and JSON_Array's.

Next we have the Create function. There’s a series of Create functions in the GNATCOLL.JSON package, each returning a JSON_Value containing the data given in its sole parameter. In our case we give Create a String, so it returns a JSON_Value where the JSON_Value_Type is JSON_String_Type.

The Length (Parents) call returns the amount (Natural) of items in the Parents array, and in the loop we make use of that number to set the range. It would’ve been nice to not have to define the lower bound of the range with an actual number. I would’ve much preferred something like Parents'Range, but hey, you can’t have it all.

In the loop we stumble on a less than pretty construction:

   Put_Line (" " & Get (Get (Parents, J)));

Gaggle! Lots of Get’ing going on there. But before you tear your hair out in frustration, lets take a look at the specification for the two Get functions used here:

function Get 
  (Arr : JSON_Array; Index : Positive) 
  return JSON_Value;
 
function Get 
  (Val : JSON_Value) 
  return UTF8_String;

Aha! Suddenly everything makes sense again. One could argue that readability could’ve been improved slighty, had the innermost call been named differently, but since that’s not the case, we’re just going to have to live with Get’ing twice.

Finally we output the JSON we’ve created:

Put_Line (Write (Penguin));

Executing the program results in this:

Yes, Penguin is a JSON object
Our Penguin is named Linux
Linux got 3 parents.
They are:
Linus Torvalds
Alan Cox
Greg Kroah-Hartman
{"parents":["Linus Torvalds", "Alan Cox", "Greg Kroah-Hartman"], "name":"Linux"}

Amazing! Now, just as there’s a Write function for turning a JSON object into a String, there’s also a Read function to turn a JSON String into a JSON_Value object:

   ...
   Pingu : JSON_Value;
begin
   ...
   Pingu := Read (Strm     => Write (Penguin),
                  Filename => "debug.file");
 
   Set_Field (Val        => Pingu,
              Field_Name => "name",
              Field      => "Pingu");
 
   Set_Field (Val        => Pingu,
              Field_Name => "parents",
              Field      => "Otmar Gutmann");
 
   Put_Line (Write (Pingu));

We Read the JSON String generated by the Write (Penguin) call into our newly declared Pingu object. The Filename parameter gives a file to where error messages are written, in case the given JSON String is mangled in some way. The two Set_Field calls overwrite the name and parents fields with new values (another famous penguin!), and finally we output the new JSON String, adding this to the previous output:

{"parents":"Otmar Gutmann", "name":"Pingu"}

Neat eh?

Using the Map_JSON_Object procedure it is also possible to iterate a JSON_Value object:

procedure Map_JSON_Object
  (Val : JSON_Value;
   CB  : access procedure (Name : UTF8_String; Value : JSON_Value));

So as you can see, you can do most everything with the tools available in GNATCOLL.JSON – there is though one thing I feel is missing: Facilities to delete fields in a JSON_Value object, but I’m sure these will come as the package matures.

For the sake of completeness, here’s the full listing of our penguin example:

with Ada.Text_IO;
with GNATCOLL.JSON;
 
procedure JSON_Fun is
   use Ada.Text_IO;
   use GNATCOLL.JSON;
 
   Penguin : constant JSON_Value := Create_Object;
   Pingu   : JSON_Value;
   Parents : JSON_Array;
begin
   if Kind (Penguin) = JSON_Object_Type then
      Put_Line ("Yes, Penguin is a JSON object");
   end if;
 
   Set_Field (Val        => Penguin,
              Field_Name => "name",
              Field      => "Linux");
 
   if Has_Field (Penguin, "name") then
      Put_Line ("Our Penguin is named " & Get (Penguin, "name"));
   end if;
 
   Append (Arr => Parents,
           Val => Create ("Linus Torvalds"));
   Append (Arr => Parents,
           Val => Create ("Alan Cox"));
   Append (Arr => Parents,
           Val => Create ("Greg Kroah-Hartman"));
 
   Set_Field (Val        => Penguin,
              Field_Name => "parents",
              Field      => Parents);
 
   Put_Line ("Linux got" 
             & Natural'Image (Length (Parents)) 
             & " parents.");
 
   Put_Line ("They are:");
   for J in 1 ..  Length (Parents) loop
      Put_Line (" " & Get (Get (Parents, J)));
   end loop;
 
   Put_Line (Write (Penguin));
 
   Pingu := Read (Strm     => Write (Penguin),
                  Filename => "debug.file");
 
   Set_Field (Val        => Pingu,
              Field_Name => "name",
              Field      => "Pingu");
 
   Set_Field (Val        => Pingu,
              Field_Name => "parents",
              Field      => "Otmar Gutmann");
 
   Put_Line (Write (Pingu));
end JSON_Fun;

I hope you’ve enjoyed reading this short introduction to the GNATCOLL.JSON package. Ada and JSON is a pretty good match, so if you don’t need or want all the complexities of XML, then give JSON a chance. The tools are available and they are pretty good.

If you’d like to see some more Ada and GNATCOLL.JSON code, try grabbing the JSON_Test project from my GitHub page, or you can read about it at the Ada-DK Wiki.

Stop the Internet Blacklist Legislation!

Today I g+’ed about the crap that is the PROTECT IP Act, but I feel the links deserve to be copied on this blog also, so without further ado:

Please go sign those petitions. Make your voice heard. I know it might not seem all that important, but believe me, it is. Every little inch of freedom we surrender is lost forever. We have to fight back now, else we’ll end up surrendering our digital lives completely to [insert random power monopoly here]. And we don’t want that. We really don’t.

The internet is a marvelous tool. It is a thing of wonder. It is worth fighting for. For the first time in the history of man have we made a tool that globally enables people to connect and share. We have built a wondrous thing that can both enlighten the oppressed and help loosen and cut the chains of the downtrodden. We should not relinquish this tool to anybody. Not big media, not government, not any business.

Fight back now. Spread those links. Make sure everybody you know signs them. Your voice matters. The internet belongs to us.

Hello world!

Yes, the title of this post is sorely missing in the creative department, but it is fitting for the first ever blog post of mine. At this point I don’t even know what to do with this blog, nor what language to use. Should I go with Danish, or fight my way through poorly spelled and grammatically disastrous English posts?

Who knows. For now I’m thinking I’ll go with English, as I’ll probably be writing mostly about technology, with a strong emphasis on programming and software in general. But I might sneak in a post in Danish once in a while, if the subject gets to complicated for my English vocabulary.

I’m going to end this introductory post with an Ada code snippet. I do so love the Ada programming language, so it’s only fitting that she’s also allowed a quick hello.

with Ada.Text_IO;
 
procedure Hello is
begin
 
   Ada.Text_IO.Put_Line ("Hello, world!");
 
end Hello;

Ahh, she’s a beauty isn’t she? The source code highlighting plugin in WP3 could though use a bit of work, or rather the CSS that goes along with it. What’s up with that massive empty area after the code?