Monday, April 11, 2011

Forth for ARM Cortex M3...

This news makes me happy :-)
I should break out my old STM eval boards and give it a try.

The last Forth (ignoring mine) that I've used was Charlie Shattuck's MyForth. Well it looks like he has created a new MyForth for the Arduino crowd. Slide here and sources here.

The nice thing about minimalism within the microcontroller world is that your end result is a "device". You don't have a lot of extra stuff (software standards, etc) to deal with.... so as long as your device interfaces correctly with outside world, the question is: Does it do something useful/interesting? Not: Did you use CouchDB, MongoDB or SQL?

Ah, the simple life.

Also, a shout out to GreenArrays for releasing initial measurements in their G144A12 spec sheet.

Ugh. I really need to find the time (and money) to play with the dev kit.

/todd

Sunday, April 10, 2011

File under "Elegant": Factorial in Plan 9 rc (under Linux)

I've posted before that I find Plan 9's rc shell elegant.  I've been using a "slightly" modified (I've made read and echo builtins) version for a few months now and have been doing extensive scripting. I hope never to go back to bash.

Here is a small script to compute factorials. Since "bc" deals with arbitrary precision, we can go much higher than the 32 or 64 bits.

Chew on this:

#!/usr/local/plan9/bin/rc
fn fac {
num=0 factorial=1 frombc=$2 tobc=$3 {
for (num in `{seq $1}) {
echo $factorial '*' $num >$tobc
factorial=`{read <$frombc}
}
echo $factorial
}
}
fn fixlinebreaks {
awk -F '\\' '{printf("%s",$1)}
$0 !~ /\\$/ {printf("\n"); fflush("");}'
}
fac $1 <>{bc | fixlinebreaks}

There are several interesting things here:
  1. Concurrent processing (co-processes actually).
  2. Messaging through unix pipes.
  3. Lazy computation (generator).
The last line launches bc as a coprocessing service (filtering output through fixlinebreaks which is needed due to a "feature" of bc where it breaks up long numbers into multiple lines -- blech).  We treat bc as a service and send it requests (steps in the factorial computation) and it responds with our intermediate results.
This factorial algorithm is iterative rather than recursive, but rather than using an incrementing counter loop, we generate all numbers using the 'seq' program and loop through that lazily generated list!

How slow do you think this script will run?  Well on my Toshiba Portege r705 notebook with a Core i3, factorial of 1024 takes 2.4 seconds. Is that slow?

Earlier I said that I had enhanced rc with "echo" and "read" as builtins (normally they are external). Using the non-builtin "echo" and "read" increases the run time to 5.1 seconds.

Of course this isn't production code, but here is the take-away: "bc" gives you a bignum calculator for free.  Use it.

Monday, March 14, 2011

Tackling the Simple Problems: The domain of the minimalist

The hard problems are more interesting by nature and the world is full of hard problems.  This blog post isn't about them. Instead, I want to talk about simple problems.

Simple problems are still problems, they just don't have world shaking impact (or so you would think).

To be honest: most simple problems are only simple on the surface.  Underneath, complexity is always lurking.

Take, for instance, my desire to (re)build a very simple blogging system (for my own personal use).  Blog software isn't all that hard to build. If you don't care about performance and scalability, then it is pretty straightforward. That is, until you get down to building one. As soon as you start thinking about security, feeds, multimedia, etc.  you start to expose the underlying complexity of "working" software.

Now, as I said earlier, this is still something of a simple problem. Developing blogger software isn't rocket science.  But, in some ways, that makes it harder.

When something is so simple (conceptually), it can be quite difficult to "get it right".  Getting it right is about hitting that sweet spot. Blogging software needs to do its simple job correctly and intuitively. If it is hard to install, or has "hard to grok" idiosyncrasies, then it doesn't solve the "simple problem" of blogging.

Consider another "simple problem".  I have around 40GB of music (mostly in MP3 format) that I want to play on my living room stereo (away from a computer). There are solutions I can buy, but none quite fit. I don't need streaming (although I would like to listen to online radio sometimes) and I don't need a "total entertainment solution".  I tend to listen to whole albums, not mixes or "randomized" selections based on genre.

All I need is a single MP3 storage device, the ability to add/delete queued albums  from any of my household PCs (web browser NOT a hard requirement), and a simple "remote" (pause, play, next song, previous song).  What I want is a music "server" and it only has to serve one sound system. (Wi-fi streaming of music is broken in my house -- too much sporadic interference).

There are server based (free!) software solutions out there, but they usually solve (only) 90% of my "simple problem".  They then throw UPnP, webservers, GUIs and all sorts of networking into the mix.  This is more than I want (after all I am a minimalist).

Note: Before computers, my problem was solved 100% by a CD player w/ 200+ CDs and before that it was solved by vinyl LPs.  Now I have a bunch of MP3s and less capability to enjoy music than when I had CDs.

Simple problems are harder than you think.

uForth Dump...and run

uForth has been mentioned here several times last year. It was my attempt at a very, very portable Forth (no dynamic memory allocation, ANSI C,  bytecode generator for portable images, etc). It has been run successfully on MSP430s as well as Windows/Linux.  No MSP430 code here unfortunately. I did most of the MSP430 code as part of my day job in 2010. It isn't mine to give away.

However, you can get a dump of the generic ANSI code here.  I haven't touched it in months and it needs documentation (and some general lovin').  Unfortunately, I don't have access to MSP430s anymore and so that is left as an exercise for the reader :-(

Monday, March 07, 2011

Notes on Mail header (and MIME) parsers...

I'm trying to resurrect my old gawk based blogging system BLOGnBOX. It (ab)uses gawk to do everything from POP3 mail retrieval (you email your blog entry...) to FTP based posting of the blog (it is a static html blog).

I intend on cleaning it up by doing away from the gawk abuses. I am either going to make it (Plan 9) rc based (with Plan 9 awk and some C for the networking) or perhaps Haskell.  That is quite a choice, eh?

I've done a bit of Haskell over the past few months and feel strong enough to do the next generation BLOGnBOX, but the main problem is actually getting the thing going. (This is a nighttime CFT and, well, I have to get into a Haskell frame of thinking).

The first task up is a parser for mime encoded email. I plan on using regular expressions (yes, I know -- use Parsec or something more Haskell-ish).  Awk is somewhat of a natural for this, but Gawk has a little more "oomph".  I can visualize how I would do it in Awk, but the Haskell is not coming naturally.

Well, it isn't all that difficult to get started in Haskell:


module MailParser where
import Text.Regex
import qualified Data.Map  as Map
type Header = Map.Map String [String]
header_regex = mkRegex "^(From|To|Subject)[ ]*:[ ]*(.+)"
parseHeader :: String -> Header -> Header
parseHeader s h = case matchRegex header_regex s
                                     of Nothing -> h
                                         Just (k:v) -> Map.insert k v h

  Well, that is a beginning. Of course, I should be using ByteStrings for efficiency...  and, yes... I know... I know... I should be using Parsec

/todd

Thursday, February 24, 2011

Rc - Making shell scripting suck less

There are some tremendous ideas behind the ubiquitous Unix shell (um, that would be Bourne, bash, (d)ash or maybe ksh?).  The problem is that a lot of these ideas are very, very dated.  Bash is probably the best example of how to keep a Unix bourne dialect alive. Ksh was beastly (tons of features), but I think bash has finally passed it.  But is this a good thing?

As I start writing more complex scripts I begin to feel the age of Bourne.  I have been using (d)ash (due to it being the Busybox shell and much smaller than bash -- GNU seem to be set on add the kitchen sink to every tool.) You can pretty much do general purpose scripting with Bash, but still with the legacy syntax of Bourne. You might as well go with Perl or Python (and their associated huge installation footprints).

Then there is rc (the Plan 9 shell). It starts with Bourne and "fixes" things rather than tack on stuff around the edges. It is very minimalistic and has a certain elegance I haven't seen since Awk.  Plan 9's toolbox minimalism was an attempt to get back to the origins of Unix (lots of small single purpose tools). The famous anti-example of this is probably GNU ls.  Look at the options, the many, many options.

Rc isn't actively supported much (Plan 9 has since faded -- if it ever shone brightly to begin with), but it has the feel of something well thought out.

You'll hear more from me about that in upcoming posts.
Time to shut up and code.

Monday, February 21, 2011

Exceptions and Errors in embedded systems

These past few posts have been ramblings to myself at the cusp of starting a new CFT (Copious Free Time) project.  I am weighing an "elegant" path (Haskell) vs a "Old Unix hacker" path (Shell scripts).

While the Haskell approach is alluring, there is a lot of learning to do there and I am an "Old Unix hacker".  I am very familiar with the benefits of functional programming and have found the past 3 months doing Haskell (some on my day job) a lot of fun.

But, I know I can get more accomplished sooner if I take a "Unix hacker" approach.

Now, for the meat of this post (and an often arguing point against using shell scripts in critical environments): Safety.

Or, more specifically, what about all of the points of unchecked failure in a shell script?
Doesn't this betray the notion of an embedded system?

Well, there is the dangerous situation of uncaught typos, but let's say we are real careful. How do we handle problems like:
1. A process in the pipeline dies unexpectedly.
2. The filesystem becomes 100% full.

Interestingly, while something like "dd if=$1 | transform | gzip >$2" looks like it can be full of the above problems, I could argue that you have this problem using any programming language/approach.

However, because it is so difficult to catch "exceptional" errors in the shell, it starts to make me wonder how I would handle this in a language that supports "exceptions".

This is where things start to unravel (for me).  What do you do in that exception? How do you recover?
Let's look at some approaches:

1. Unix approach:   Wrap the "dd" line in a script and have a monitor start it, capture and log stderr and restart it if necessary (but not too aggressively -- maybe at some point give up and shutdown the system).
2. Erlang approach:  Interestingly similar to above.
3. Language w/ exceptions: Catch the error, close the files and.... um, restart?

In the Unix approach, the cleanup is mostly done for you. Good fault tolerance practice (as suggested by Erlang) is pretty much handled by variants of init (I believe that daemontool's supervisor has been doing this well for years).

I am sure there are holes in my argument, but for my CFT, I am persisting all important data on disk (an event queue is central to my system). Every change (addition, execution, removal) of an event is an atomic disk transaction. If any process dies, it can be relaunched and pick up where it left off.

For fault tolerant (embedded) systems I am not sure what I would do in an "exception" handler... outside of clean up and die.

/todd

Haskell scripting for robust embedded systems...

A convincing (unrelated) counter view to my prior posts here: Practical Haskell: scripting with types.

Sunday, February 20, 2011

Unix Shell scripting for robust embedded systems

The summary/ramification of my previous post:

Shell scripting (in this case Busybox) is a viable approach to developing robust, long running embedded systems. 

If you can afford to run a (multi-tasking, memory managed) Linux kernel in your embedded system and Busybox is there, then the shell (ash in this case) becomes a potential basis for a system architecture.

Of course, this is not breaking news. But I think it gets lost when we start taking a " single programming language" view of system development (as advocated by almost every modern programming language).  If you are trying hard to figure out how to get your favorite programming language to do what the shell does, then maybe it isn't the right tool for the job. 

Sure, the "shell" isn't elegant and is full of pitfalls and gotchas when you use it beyond a couple of lines, but when your shell script starts to grow, you too should consider looking elsewhere for help (i.e. commands beyond what is built into the shell).

An example: Don't get caught up in gawk/bash's ability to read from TCP sockets, leverage netcat (nc).

/todd

Haskell vs Busybox (for an embedded soft-realtime control system)

I'm building an embedded soft-real-time control system. It will handle sensor events and provide feedback to the user using voice synthesis.

I really want to use Haskell for this CFT project, but I can get something running so much quicker by shell scripting.  There won't be a lot of sophisticated algorithms and I don't see scalability as a concern.

When it comes down to it, I am find it harder and harder to do system programming in a "programming language" vs something in a shell (with support from awk and friends).  It doesn't matter if it is C or Haskell, it starts to feel like (once again) re-inventing a wheel.

As an example (and it has nothing to do with this current CFT project), consider this problem: I want to transform 1024 byte chunks of a file and write the results as a compressed file. The transformation doesn't matter, but let's say the transformation is written in C (or Haskell for that matter) and takes 50-100 ms per 1024 byte chunk.

I want to do this task as fast as possible. I have (at least) 2 CPU cores to work with.  Let's look at two approaches:

Approach A:   Write a Haskell/C program to read 1024 bytes at a time, perform the translation, then the compression  and write the 1024 bytes to an output file.

Okay, so I need to link in a decent gzip compression library and I use an appropriate "opt" parser to grab the input and output file.  Done.

Approach B:  dd if=$1 bs=1024 | translator | gzip > $2

This assumes that I write the same core "translator" code as above, so we can ignore that and focus on reading, compression and writing.

You can guess which will take shorter to implement, but which is the more efficient?

Well, my wild guess would be Approach B. Why? Well I already have a couple of things going for me. One is that I have automatic concurrency! While "dd" is just sitting there reading the disk, translator is running and gzip is also doing its thing. If I have 3 cores, then I have a good chance that each process can run in parallel (for at least a little while before they block). There is some cost in the piping, but that is something that linux/unix is optimized to perform.  Given that, "dd" has a good chance of causing more efficient file input buffering than my single threaded app in Approach A. The dd process has disk buffering + pipe buffering working for it so it may fetch (and dispatch) several 1024 byte chunks before it blocks on a full pipe.  A similar (but reverse) caching is happening with gzip too.

So, you then consider rewriting Approach A but using a concurrency module/library.  Ugh. Let's not go there.

So, if I take a scripting approach, my "controlling" part of the system can be written using the Shell and I can optimize to Haskell (or C) as needed.

The Wisdom of Unix shell scripting for systems

Prototype with Perl, Ruby, Python, Tcl, etc and to optimize you have to dive into using an FFI (foreign function interface).

Prototype with a Unix/Linux shell (bash, ash, ksh, etc) and to optimize you rewrite proc/commands in your favorite (compiled?) language and use stdin/stdout as the interface.

When piping makes sense (or concurrent processes with lightweight I/O requirements), 30+ years of shell wisdom is your friend.

If shell scripts can be trusted to boot your Unix/Linux distribution, can the shell be trusted as the controller/glue for your application?

/todd

Monday, February 07, 2011

Haskell Revelation -- Optimizing via refactoring

I have some code that lazily transforms a fairly large list of data (from an IO source) that must be search sequentially. Since it is lazy, the list isn't fully transformed until the first search. Since, I presume, a rather large stack of thunks are constructed instead, this first search takes a really, really long time. (It would be faster, I surmised, to strictly transform the list as it was being built, rather than lazily upon the first search).

I started playing with `seq` but couldn't quite get the strictness right -- the code represented some of my first attempts at Haskell.  So, I decided to refactor the code (replace naive tail recursion with maps, filters, folds, etc). I figured at this point I would be able to see more clearly how to avoid the lazy list.

Surprisingly, this refactoring was enough for the compiler to "do the right thing" and sped my application up significantly. What was the compiling doing here? Did it remove the laziness? Or did it just optimize the hell out of what I thought was a lazy vs strict problem?

/todd

Monday, January 24, 2011

How low can Haskell go? (Or what should I do with Haskell?)

Is Haskell a suitable language for programming robots?  Would a robot with a strictly functional brain be safer?  I have run a fairly hairy 2K line Haskell app on a target as small as an Atom based netbook.  It ran reasonably.

I suppose, for a linux target, that a Haskell executable is pretty much like any other executable.

What is the benefit to taking a purely functional approach to robotics?

For some pioneers (think Greenblatt, Stallman, etc) Lisp was a "systems programming" language. Is Haskell a reasonable successor?

These are questions I am pondering.  I am doing some Haskell (here an there -- prototyping stuff at work, etc), but I keep wondering what the killer application would be *for me*.

Sunday, December 05, 2010

Important techniques for (future) multi-core embedded development

These three approaches intrigue me:  Staapl, Lava and MyForth. They don't address "multi-core embedded processors ", but I think their "meta system" approach will be integral in making it easier to developer for embedded multi-core controllers.

Tuesday, November 23, 2010

The Lonely Programmer (Hacker)

I've been noticing books on the market (and some blogs too) that speak of our newly emerging "Maker" culture -- a culture where people fed up with intangible abstract work (do you sit in a cubicle pushing numbers?) are turning to the gratification of hands on creation. They say that working on physical things can give you a deep sense of accomplishment that nurtures our primordial tool building minds.

I put forth that some programmers can get this feeling from the intangible and abstract.  I grew up working with my hands (art, electronics, and just generally building stuff).  Programming became an extension of that. It my mind, my code held the same sense of accomplishment and gratification as building something with my hands.  I became enamored with virtual worlds!

Nowadays, however, I find that a lot off programmers spend significant time worrying about languages, syntax, test coverage and code re-use. These are topics of varying importance, but they are just about honing your skills.  At some point you have to produce something. Hopefully it is beautiful (not just on the outside but inside too).  How you managed to create it (the language, test approach, etc) is secondary to the thing itself. And, oh, if it is malleable and can be adapted to do new exciting things, is that proof enough you used good coding techniques?

We spend so much time talking about the tools, we forget that it is the result that matters. We forget about the joy and awe of working code.  We instead tend to form language advocacy groups, cult-like methodologies and obsess over software licensing.

Really, if someone were to create a fully aware artificial being capable of not only passing the Turing test but able to engage us in deep conversation, would we (the programmers) nitpick over how poorly the code is structured, the lack of test coverage and how terrible it is that it was implemented in a crappy programing language?

Thursday, November 11, 2010

MP3 ID3v1 tag reading in Perl and in Haskell

I am building an MP3 jukebox for my home...

I know that I am supposed to use ID3v2, but my MP3 collection (CD ripped, Amazon and Emusic) still sports ID3v1 tags, so I thought it would be a safe  bet to just parse it.

I quickly wrote an ID3v1 tag parser in Perl (yes, I know CPAN has several solutions for this but I wanted to write my own just for the fun). Here is what it looks like:


use strict;
use warnings;
use Fcntl qw(:seek);


my @genre = (
'Blues','Classic Rock','Country','Dance',
'Disco','Funk','Grunge','Hip-Hop',
'Jazz','Metal','New Ag(e','Oldies',
'Other','Pop','R&B','Rap',
'Reggae','Rock','Techno','Industrial',
'Alternative','Ska','Death Metal','Pranks',
'Soundtrack','Euro-Techno','Ambient','Trip-Hop',
'Vocal','Jazz+Funk','Fusion','Trance',
'Classical','Instrumental','Acid','House',
'Game','Sound Clip','Gospel','Noise',
'AlternRock','Bass','Soul','Punk',
'Space','Meditative','Instrumental Pop','Instrumental Rock',
'Ethnic','Gothic','Darkwave','Techno-Industrial',
'Electronic','Pop-Folk','Eurodance','Dream',
'Southern Rock','Cult','Gangsta','Top 40',
'Christian Rap','Pop/Funk','Jungle','Native American',
'Cabaret','New Wave','Psychadelic','Rave',
'Showtunes','Trailer','Lo-Fi','Tribal',
'Acid Punk','Acid Jazz','Polka','Retro',
'Musical','Rock &','Hard Rock','Folk',
'Folk-Rock','National Folk','Swing','Fast Fusion',
'Bebob','Latin','Revival','Celtic',
'Bluegrass','Avantgarde','Gothic Rock','Progressive Rock',
'Psychedelic Rock','Symphonic Rock','Slow Rock','Big Band',
'Chorus','Easy Listening','Acoustic','Humour',
'Speech','Chanson','Opera','Chamber Music',
'Symphony','Booty Brass','Primus','Porn Groove',
'Satire','Slow Jam','Club','Tango',
'Samba','Folklore','Ballad','Power Ballad',
'Rhytmic Soul','Freestyle','Duet','Punk Rock',
'Drum Solo','A Capela','Euro-House','Dance Hall' );


my $id3v1;
my $id3v1_tmpl = "A3 A30 A30 A30 A4 A28 C C C";


while (my $filename = ) {
    chomp $filename;
    open my $fh, '<', $filename or next;
    binmode $fh;
    seek $fh, -128, SEEK_END and read $fh, $id3v1, 128;
    close $fh;
    my (undef,$title,$artist,$album,$year,$comment,undef,$trk,$genr) =
unpack($id3v1_tmpl,$id3v1);
    print "$filename|$title|$artist|$album|$year|$trk|".$genre[$genr]."\n";
}

Basically it takes a stream of MP3 filenames over stdin, opens them and dumps out a pipe delimited summary of what it found. Here is how it is run:

$ find /home/todd/music -name "*.mp3" | perl mp3info.pl >mp3_data.txt

Here is a line from the output (mp3_data.txt):
/home/todd/music/Charles Mingus/Ah Um/Charles Mingus_10_Pedal Point Blues.mp3|Pedal Point Blues|Charles Mingus|Ah Um|1959|10|Jazz

I am considering using Haskell for my jukebox, so I was curious what this would look like in Haskell.  Here is my newbie Haskell implementation:

import Text.Printf
import Data.Array
import Char
import System.Environment
import System.IO

-- Create a array of genres
genres = listArray (0, l-1) genres_l 
         where 
           genres_l = [
             "Blues", "Classic Rock","Country","Dance",
             "Disco","Funk","Grunge","Hip-Hop",
             "Jazz","Metal","New Age","Oldies",
             "Other","Pop","R&B","Rap",
             "Reggae","Rock","Techno","Industrial",
             "Alternative","Ska","Death Metal","Pranks",
             "Soundtrack","Euro-Techno","Ambient","Trip-Hop",
             "Vocal","Jazz+Funk","Fusion","Trance",
             "Classical","Instrumental","Acid","House",
             "Game","Sound Clip","Gospel","Noise",
             "AlternRock","Bass","Soul","Punk",
             "Space","Meditative","Instrumental Pop","Instrumental Rock",
             "Ethnic","Gothic","Darkwave","Techno-Industrial",
             "Electronic","Pop-Folk","Eurodance","Dream",
             "Southern Rock","Cult","Gangsta","Top 40",
             "Christian Rap","Pop/Funk","Jungle","Native American",
             "Cabaret","New Wave","Psychadelic","Rave",
             "Showtunes","Trailer","Lo-Fi","Tribal",
             "Acid Punk","Acid Jazz","Polka","Retro",
             "Musical","Rock &","Hard Rock","Folk",
             "Folk-Rock","National Folk","Swing","Fast Fusion",
             "Bebob","Latin","Revival","Celtic",
             "Bluegrass","Avantgarde","Gothic Rock","Progressive Rock",
             "Psychedelic Rock","Symphonic Rock","Slow Rock","Big Band",
             "Chorus","Easy Listening","Acoustic","Humour",
             "Speech","Chanson","Opera","Chamber Music",
             "Symphony","Booty Brass","Primus","Porn Groove",
             "Satire","Slow Jam","Club","Tango",
             "Samba","Folklore","Ballad","Power Ballad",
             "Rhytmic Soul","Freestyle","Duet","Punk Rock",
             "Drum Solo","A Capela","Euro-House","Dance Hall" ]
           l = length genres_l

main = do

  hSetEncoding stdin latin1
  hSetEncoding stdout latin1

  fname <- getContents          -- lazily read list of files from stdin
  mapM print_id3v1 (lines fname)
    
print_id3v1 fname = do
  print fname
  inh <- openBinaryFile fname ReadMode
  hSeek inh SeekFromEnd (-128)
  dat <- hGetContents inh
  printf "%s|%s|%s|%s|%s|%d|%s\n"
       fname
       (extract 3 30 dat)      -- Title
       (extract 33 30 dat)     -- Artist
       (extract 63 30 dat)     -- Album
       (extract 93 4 dat)                              -- Year
       (Char.ord (head (extract 126 1 dat)))           -- Track
       (genres !(Char.ord (head (extract 127 1 dat)))) -- Genre
  hClose inh

-- extract and trim a range of elements from list
extract idx ln s = 
    trim0 (take ln (drop idx s))

-- Trim nulls from list
trim0 s = filter (/= '\0') s

You run it similarly. Frustratingly, it isn't very happy with filenames with non-ASCII characters :-(

$ find /home/todd/music/ -name "*.mp3" -print | ./mp3info >mp3_files.txt 
mp3info: /home/todd/Music/music/Ch�ying Drolma & Steve Tibbetts/Selwa/Ch�ying Drolma & Steve Tibbetts_05_Gayatri.mp3: openBinaryFile: does not exist (No such file or directory)

I am not a Haskell expert, but I didn't expect it to choke there...

EDIT: Fixed the filename problem by adding:

  hSetEncoding stdin latin1
  hSetEncoding stdout latin1

Tuesday, October 19, 2010

Future runtime environment for Robots

Embedded systems are getting smaller and more sophisticated. While there are currently bare ARMs and 8/16-bit micros controlling our mainstream robots, this won't do for the more sophisticated (domestic) robots of the near future.

When we consider sophisticated robots (whether ruled by a subsumption architecture or other invariably concurrent system), we won't think of Python, Java, Ruby or Perl. We will be thinking of something more Erlang-like or perhaps Unix-y.

Can you imagine jacking into your robot's debug port, typing "ps" and seeing a collection of inter-communicating processes running on a Linux kernel?  Or will it be something like Erlang/OTP?  (Erlang is the dark horse here... Unix may never go away as a platform.)

So, how about it? Erlang on a gumstix?

Friday, September 10, 2010

New AFT release!

AFT development has dormant for about 1 year, so I decided to reboot it with a minor (experimental) release (5.098) that supports Indexing. This is mostly useful for LaTeX output. I'm not sure how useful the HTML output will be.

I've also started to clean up the Perl source for AFT.  I am currently reading the new edition of Effective Perl Programming and hope to apply more idiomatic Modern Perl conventions to the 14+ year old AFT sources.

As always, AFT is available through "sudo apt-get install aft" under Ubuntu (and Debian?). But to get this new release, go to the AFT website. (For a quick look at Indexing in action, look at the aft reference manual and scroll to the last page).

I need to start archiving my art...

This is an airbrush I made 23 years ago:
Miles Davis


I need to scan in all my old artwork and figure out the best place to post them.

Wednesday, September 08, 2010

I miss Perl...

I've been going through my old books and came upon a stash of Perl tomes.  I had a love/hate relationship with Perl. I wrote AFT in Perl, but have not used it as my language of choice in (almost) a decade.

Stumbling across these books got me wondering: Where have all the Perl hackers gone?

Well, I can't say where they have all gone (Ruby? Python? Retirement?), but I miss the funky vibe that Perl had in it's day.  Perl was messy, but the language attracted the most interesting people.  I've always seen it to be the language of poets (as opposed to engineers).  Perl people loved wordplay. Perl people weren't just interested in producing interesting apps, but also making the app source code look interesting.

Well, Perl isn't gone. Apparently, strides have been made in Perl 6 and Rakudo is available for playing around with a lot of Perl 6 features.

But, will the hackers come?

I am reminded of a quote from Ratatouille (Colette introducing the kitchen staff to Linguine):
 "... So you see: We are Artists. Pirates. More than cooks are we."