Tuesday, July 28, 2009

Testing in Perl 6

So, here's my first hesitant step to building Perl test code (specifically Perl 6 in this case, but I've never used any of the Test modules for Perl 5, either).

Simple and short, but with it I learned a significant limitation of my STEP extract script and turned up a Rakudobug. All in all, a most successful first foray into testing Perl code.

Now all I need to do is figure out the proper directory structure, and how to automatically build a makefile with a "test" target, and get the hacked version of Test.pm which properly handles planless testing.

Friday, July 24, 2009

Quick Bits

I have to report a complete FAIL on trying to install Padre + its Perl 6 extensions on my OS X. The Perl 6 stuff required me to install 5.10.0 from source, and even after I hand-hacked Mac::File so it would install, some other CPAN dependency that didn't install properly tripped me up, and I gave up on it. I may try again at a future date, but since I am unlikely to give up TextMate for Padre anyway, and my free time is actually negative at the moment, it seems a very low priority.

It also seems to have trashed my ability to run the STD.pm from Pugs -- looks like it may have installed its own non-compatible STD.pm? I haven't had time to investigate this yet.

On the bright side, Rakudo's "Chicago" release installed smoothly (and this time I had the good sense not to install it over my main Rakudo installation until I verified that it worked).

I am in awe of this script from pmichaud. Yes, that craziness works just fine in Chicago. I was very confused by the @deck .= pick(*); line, until I remembered that dot is now strictly used for member functions (or whatever the proper Perl 6 term is) -- thus it is really just shorthand for @deck = @deck.pick(*);. Once you know that pick picks random members from an array, then it's more-or-less clear that @deck.pick(*) returns a shuffled deck.

I'm working on trying to establish tests for my STEP extract script. I'm stuck on trying to figure out how to get the results back from an external command in Perl 6, but I'm sure I'll work it out sooner or later.

Tuesday, July 21, 2009

Perl 6 Taking Off

I read masak's post yesterday, and nodded my head in agreement, but didn't really think too much of it. Then last night I realized I could really use a Perl script to analyze the (C++) bug I was dealing with for work. And I thought about it a second, gulped, and started writing it in Perl 6.

Now, this wasn't the first work script I'd done in Perl 6. About six months ago I did a very handy little TextMate script in it. But writing that was a nightmare -- in fact, it turned out the feature that was the reason I wanted to use Perl 6 for the script wasn't actually implemented yet. I stuck with it, and with a lot of trial and error got a script that worked, but it wasn't fun or easy.

What a difference six months makes! My project was night was a classic simple Perl script, reading a text file, processing it a tad, and writing it back out in another format. The script took only marginally longer to write than it would have in Perl 5. Part of it was my much increased familiarity with Perl 6, no doubt. But I never ran into Perl 6 limitations at all! Everything I wanted to use was implemented and worked like a charm. There was one error message that could have been clearer, and that was it.

Big kudos are due the Rakudo team for making so much progress this year! Things are getting very exciting in the world of Perl 6...

Sunday, July 19, 2009

Perl 6 At Work

So, the Perl 6 script I talked about in my last two posts is now every bit as functional as the Perl 5 script it is descended from. And while I certainly recognize there is more to do to improve this script (both in better Perl 6 code and improved user interface), I can't begin to say how excited I am by this script. It really feels like a proper Perl 6 script at this point, and it strikes me as clearly superior to the Perl 5 version.

What do I like about it? The GetMatches sub is elegant in the way it takes a Regex and allows me to replace five lines of fairly hacky Perl 5 code with a single elegant line of Perl 6. And the given/when construct is a much cleaner way of handling command line arguments. (Admittedly this also gained over the Perl 5 version by eliminating dead code for ways I thought I would use the original script when I first wrote it.) Overall, the code has gotten significantly more element than the Perl 5 version, despite the fact that Perl 6 isn't finished yet.

Oh yes, what does this do? It extracts entities from a (Part 21 encoded) STEP file, including all the sub-entities that entity depends on. This is invaluable for debugging STEP support.

Improvements? In terms of Perl 6 usage, I'd love to get rid of the loop at the end that only does say. I guess I could use map for that, but just as I didn't like the thought of using map and ignoring its inputs, I don't like the thought of using map with side-effects.

I also wonder if the given statement is even needed. Can when be used with $_ from a for loop? And I look at the split loop and wonder if that could be more elegantly written in terms of my GetMatches function.

In terms of general code, I think there would be benefits from switching the entity references to straight numbers instead of numbers proceeded by a '#'. I'd certainly like some usage information. The code would be more reliable if it actually parsed the STEP data with some rules -- right now it's assuming that no one will ever use a semi-colon in a string in one of these files, and while that's never really caused me trouble in the past, it is a rash assumption. And I'd like to have support for tracing each entity's usage up to the top level to get its STEP context, which can be very important for imported. (Right now I do that sort of thing by hand after letting the script do the dirty work.)

Updated: Oh yes, for/when works every bit as well as given/when!

Updated again: One thing I'd really like to do is set up some tests for this -- if nothing else, it would make improving the script easier. Does anyone have hints on testing in Perl 6?

Wednesday, July 15, 2009

Getting STD.pm to work

In a comment to my last post, moritz suggested STD.pm would be a better check for the validity of my code as I ported it from Perl 5 to Perl 6. I duly set out to figure out how to do this -- and since I didn't find any hint of how to do it with a Google search, I'll document it here in hopes it helps someone else.

The legendary TimToady pointed me in the right direction. First, STD.pm and the scripts for using it live in the Pugs repository. I got http://svn.pugscode.org/pugs, though it may be possible to just get the src/perl6 directory tree, as that is the one we are interested in.

Once you have that src/perl6 directory, cd to it. You need to make to get it ready to use. Unfortunately, it is hardcoded to assume Perl 5.10 is available in /usr/local/bin/perl. If, like me, you only have 5.10 installed as a local user, you will need to go through the code and replace that path with the path to your Perl 5.10. (This is a great application for a quick Perl script.) You also need to have Moose and YAML::Syck installed. (I should thank moritz and PerlJam for helping me with getting this directory prepped to work.)

If you get that all set up and execute make and it doesn't return any errors, then you should have a working STD.pm! The tryfile command will try to parse your Perl 6 file carefully and provide sensible error messages.

Tuesday, July 14, 2009

Perl 6 Parsing Generously?

I just started a new little Perl 6 project by grabbing a little 99 line Perl 5 script, sticking use v6; at the top, and running it through Rakduo. Much to my surprise, a lot fewer things were complained about than I expected. (So far, I'm only about one-third through the first stage of the port.)

It did complain about my $in_file = shift; to store the next value from @ARGV/@*ARGS, about foreach $arg (@*ARGS), and about using dot from string concatenation. But it did not complain about if ($arg =~ /^\-sd/), for ($i = $1; $i <= $2; $i++), or open IN_FILE, $in_file or die. I wouldn't have expected any of those to get through the parser? (I'm assuming they'll fail when the code finally is ported enough to reach proper execution.)

I'm also trying to figure out how to automatically test this script. I guess I can easily enough throw a few files at it and check to make sure the results are correct. Does it make sense to try to unit test something this small? (As it is, the Perl 5 version has no subs at all!) And what is the accepted way of doing such testing in Perl 6?

Tuesday, July 7, 2009

Dice Game Again

After seeing Daniel Ruoso's lovely version, I decided to take another crack at the the dice game:

Notice that once the payback subroutine is defined, the all the calculations are done with a simple one-liner, followed by a single say to print the results, and then wrapped with MAIN to produce a command-line interface. Wee!

Alas, I believe this would be the slowest version yet but for the fact I replaced * with $_ in the given / when statement.

Monday, July 6, 2009

Dice Game Perl 6

Saw this lovely piece of Perl 5 code this weekend and decided to try to duplicate it in Perl 6. For my first attempt, I ended up reverting back to the original because I have no idea how to get the sweet features allowed by Pod::Usage, Getopt::Long, and Number::Format in Perl 6. But even this first simple attempt is significantly nicer than the Scala original IMO.

This is one example where the chained comparison operators really pays off in making cleaner and easier to understand code. The need to declare an object just to declare a function is a dumb feature Scala carries over from Java. Using say the way I have used it here pales in comparison to Perl 5, but is definitely cleaner and nicer than Scala's printf. And I don't see any advantage here to having a Random class instead of a simple rand function.

Downsides to Perl 6 (other than currently lacking the CPAN glory of the Perl 5 version, so far as I know): It's definitely slower than I would like. And not only is it slower, but it is progressively slower: 16 seconds if I use (10000, 500, 1000) plays, 4 minutes and 9 seconds if I take ten times those numbers, rather than the 2 minutes 40 seconds you would expect.

Potential improvements: Maybe given when instead of those chained ifs. Wonder how that would compare performance wise?

Friday, July 3, 2009

I'm Not Afraid of Change...

... but I am starting to get a bit worried about the Perl 5 maintainers.

Let me try to explain my point of view more clearly. That 11,000 lines of code of mine represent a significant technological debt for my company. I've learned a lot about Perl since I wrote the bulk of it, and Perl itself has progressed considerably in that time. It isn't well-written, or well-commented, and it certainly isn't tested, other than in the sense that its output is mostly used and seems to work fine.

Luckily, for the last decade of Perl 5 development, I have effectively had an interest-free loan on that debt, so it has only been an issue on the rare occasions I have had to update the code.

Now, as I see it, a new version of Perl can do one of three things to that debt:

1) It can add to it, or force me to pay it off all at once. People keep on blithely suggesting simply keeping old copies of Perl around to run the old software. But with 5+ different platforms to worry about and me hoping to write my new Perl code using new features, this would quickly become a significant new source of technological debt. Likewise being forced to rewrite the code without getting something useful from it.

2) It can keep the technological debt the same. This would be the case if my old code works fine with a few changes, but I cannot easily access new features without completely rewriting my code. In this case, upgrading Perl 5 would be painless, but would only make a difference in newly written code.

3) It can actually reduce the debt. This could be because the old code works with few changes and actually works better -- faster, or automatically detects real errors instead of just nagging me about clumsily written code that works. Or it could be because I can make the old code work easily without blocking my access to the bulk of the new features, and those features are actually really easy to use to make the old code better.

Unsurprisingly, I'd be unhappy if updates to Perl 5 fell into category 1, reasonably happy if they fell into category 2, and ecstatic if they fell into category 3.

What has me now worried about this process is no one seems to be claiming the changes fall into category 3. If all it takes is no strict; no warnings; and maybe a couple of minor tweaks to the code (carefully and automatically pointed out by Perl 5 itself, ideally) to make a range of cool new features available, then I'm excited by that, and I would certainly expect the vast majority of the DarkPAN would be at least okay with it.

Instead, people are making it sound like we can expect most future Perl 5 updates to be like taking some unpleasant but necessary medicine. I don't see how the DarkPAN can really object if it only takes one line of code or a command-line switch to make the Perl 5 of the future act just like the Perl 5 of the past. So when I see comments like "Fuck DarkPAN", I start to get worried that people are envisioning changes that are both major and not easy to ignore.

Wednesday, July 1, 2009

Silent Majority?

NPEREZ asks, "Who are these people that have a vested interested in Perl and yet do not participate?" Well, I guess until very recently I was one of them.

The core of my professional work is a set of C++ libraries. But there are 11,000 lines of Perl 5 code split across about 30 programs which are essential components supporting those libraries. Most of it is generating things, including 95,000 lines of C++ code and hundreds of makefiles, VC++ projects, etc. The Perl 5 I use is either the vendor-supplied Perl (on my Linux boxen and my MacBook) or ActiveState on Windows; my development environment requires that most of that 11,000 lines runs on every platform I use.

In this context, Perl 5 has just plain worked for me for the last decade. With a fresh Linux install it usually takes me about five minutes to get the modules I use off of CPAN and than I'm up and running. I can't recall ever having an issue with using a different version of Perl for this; it just has always worked, quickly and easily.

Given that, why would I have "participated" in steering Perl 5? I'm a busy guy, and Perl 5 has been steered perfectly for my purposes without my contribution. It took Perl 6 to draw me into the community. Now that I'm following a number of Perl blogs (thank you Iron Man), I'm taking an interest in Perl 5 development as well, because I'm excited about the newer modules I am learning about.

So I come to this issue from both sides. On the one hand, I'm very excited about new developments in Perl (both Perl 5 and Perl 6); I'm correspondingly disappointed that 5.10 has not been widely adopted, because that slows my own use of it. (Though after seemingly good results compiling a "personal" 5.10 on one of my Linux boxen, I may try switching to this approach, leaving the vendor Perl for the system to use and upgrading the version I use personally.)

On the other hand, I'd be pretty put out if someone gratuitously broke all my scripts. (The proposed idea of making "use strict" default would do it nicely, breaking all but the most recent.) I guess if the breakage could be controlled by a command line switch it would just be a minor nuisance. Otherwise the cost would likely be somewhere between days of work and simply refusing to ever update Perl 5 again.

Having just taken my first steps into the community, I don't feel like the me of six months ago somehow deserved to be screwed over just because I wasn't really part of the community then. From my perspective, the Perl community did a fantastic job of steering the language through 5.005, 5.6, and 5.8; to the extent there has been a bit of a fumble with 5.10, it seems to be the lack of updates more than the changes to the language. I'd like to see that great work continue along similar lines.