Saturday, December 5, 2009

Extra parsing for better errors

Something that I think is a unique feature of Perl 6 is that it goes out of its way to parse things that aren't in the language so that it can give you a really good error message. For instance, in Perl 5 and other C-like languages there is a for loop that looks like this:

for (EXPR ; EXPR; EXPR ) BLOCK

Perl 6's version of that loop doesn't start with "for" since it uses "for" exclusively as an iterator of lists. However, if you happen to write a for loop as above, there is code in the standard Perl 6 parser that matches it and tells you what you did wrong and how to fix it. If you read the grammar for Perl 6, you find this sort of thing all over the place.

Perhaps it's just that Perl is in the unique position of having two major versions of the language that have significant differences in syntax and semantics that such extra parsing is almost required. But, I wonder how many other languages do this to the extent of Perl 6?

Tuesday, December 1, 2009

an annoying meme

I've been following the twitterverse off and on for a while now. Quite often the "Perl is dead" meme rears it's ugly head and I have to wonder why there is such animosity towards Perl. Sometimes it's just ignorance (occasionally willful ignorance) about the state of Perl, but many times it's random vitriol against Perl.

Perl is clearly not dead.

There are easily 5 or 6 conferences a year on Perl. Off the top of my head, there are 3 YAPCs (Yet Another Perl Conference): YAPC::NA, YAPC::EU, YAPC::Asia; The Perl Conference; The Nordic Perl Workshop; Frozen Perl. There are probably several I've forgotten or just don't know about as well. CPAN still has continuous contributions and growth. There are bunches of blog posts about perl every day (See the Perl Ironman challenge). Et cetera.


So what do these people have against Perl that they would say it is "dead"? Does its continued existence cause them such pain? Why do they stomp all over Perl? If they don't like Perl, that's fine. I don't like COBOL. If the topic comes up, I might mention that I don't like it. However, I don't go around saying that COBOL is dead.

Also, what do they get out of it? I think it's the rise they get out of Perl people. Blog posts like this one or even the twittered responses of "Perl is not dead" satiates their child-like desire to gain attention by picking on Perl much like siblings pick on each other.

Maybe we Perl people should wear the "Perl is dead" meme as a badge of honor. I mean, in a way it's nice to know that they consider Perl such a threat that they keep attacking it.

I don't know ... this particular meme just bugs me.

Thursday, October 22, 2009

Awkward edits

Am I the only one who has trouble doing a simple cut-n-paste into the edit box for Blogspot to generate a post? Simple HTML suddenly gets less simple. :-(

Rakudo Perl 6 development release #22 ("Thousand Oaks")

Announce: Rakudo Perl 6 development release #22 ("Thousand Oaks")


On behalf of the Rakudo development team, I'm pleased to announce the October 2009 development release of Rakudo Perl #22 "Thousand Oaks". Rakudo is an implementation of Perl 6 on the Parrot Virtual Machine (see http://www.parrot.org). The tarball for the October 2009 release is available from http://github.com/rakudo/rakudo/downloads

Due to the continued rapid pace of Rakudo development and the frequent addition of new Perl 6 features and bugfixes, we recommend building Rakudo from the latest source, available from the main repository at github. More details are available at http://rakudo.org/how-to-get-rakudo.

Rakudo Perl follows a monthly release cycle, with each release code named after a Perl Mongers group. The October 2009 is code named "Thousand Oaks" for their amazing Perl 6 hackathon, their report at http://www.lowlevelmanager.com/2009/09/perl-6-hackathon.html, and just because I like the name :-)

Since the 2009-08 release, Rakudo Perl builds from an installed Parrot instead of using Parrot's build tree. This means that, unlike previous versions of Rakudo Perl, the "perl6" (or "perl6.exe") executables only work when invoked from the Rakudo root directory until a "make install" is performed. Running "make install" will install Rakudo and its libraries into the Parrot installation that was used to build it, and then the executables will work when invoked from any directory.

This release of Rakudo requires Parrot 1.7.0.

For the latest information on building and using Rakudo Perl, see the readme file section titled "Building and invoking Rakudo". (Quick note: the "--gen-parrot" option still automatically downloads and builds Parrot as before, if you prefer that approach.)

Some of the specific changes and improvements occuring with this release include:


  • Rakudo is now passing 32,582 spectests, an increase of 17,085 passing tests since the September 2009 release. With this release Rakudo is now passing 85.0% of the available spectest suite.
  • We have a huge increase in the number of spectests relating to the Complex and Rat numeric types.
  • Complex numbers are now implemented as a Perl 6 class, and supports all trigonometric functions from the specification.
  • Rakudo has a new signature binder which makes calling routines and operators much faster, and allows binding of positional arguments by name.
  • Rakudo has improved signature introspection, better errors relating to signatures and signature literals are now supported.
  • Rakudo now supports accessing outer lexical variables from classes and packages.
  • Some new variants of the series operator are now implemented.
  • When configuring Rakudo with --gen-parrot, the --optimize flag is now passed to Parrot's Configure.pl


The development team thanks all of our contributors and sponsors for making Rakudo Perl possible. If you would like to contribute, see http://rakudo.org/how-to-help , ask on the perl6-compiler@perl.org mailing list, or ask on IRC #perl6 on freenode.

The next release of Rakudo (#23) is scheduled for November 19, 2009. A list of the other planned release dates and codenames for 2009 is available in the "docs/release_guide.pod" file. In general, Rakudo development releases are scheduled to occur two days after each Parrot monthly release. Parrot releases the third Tuesday of each month.

Have fun!

Thursday, October 8, 2009

Perl around the world.

Maybe it's just that I'm so very American but I've been reading the posts from the Perl Iron Man challenge and I'm amazed and excited at how many posts there are in other languages. Just now I've seen Spanish, French, German, and what I think is Russian. Yes, I know that Perl is spoken around the world, but, for me, it's neat to see a microcosm of the world. Sometimes these posts seem interesting from the code that they present, but unfortunately I'm too much of a monoglot.

Anyway, Perl++

Sunday, October 4, 2009

Catalyst Sparklines

At work we maintain several platforms along the Texas coast that collect various physical parameters in or near the waters of the Gulf of Mexico or bay systems. In order to maintain the quality of the data, we have a QC process that displays a series of graphs that show the last 7 days of data collected at each station. A human reviews these graphs each morning to look for potential problems which are noted and forwarded to the field crew and the IT staff so that they may be resolved.

Over the last few months one of the ideas that's come up to improve the QC process is to use sparklines to get a high level overview at a glance rather than the larger graphs that we currently use. Since we're in the process of turning this legacy application grown over the last 19 years into something that uses more modern tools such as Moose and Catalyst, I thought I'd see how difficult it would be to implement sparkline-QC in Catalyst.

Turns out it was ueber-easy because earlier today I ran across this entry in last year's Catalyst Advent Calendar. So, now in the span of an hour or so I've got a working prototype generating sparklines for all of the data series at each station similar to the way we generate graphs for our QC page. Hooray for Perl, CPAN, and Catalyst!

Saturday, September 26, 2009

Unit Tests, Heroes and Duct Tape

Recently, a friend twittered about an article by Joel Spolsky entitled The Duct Tape Programmer:
OMG, Spolsky is praising his hero--WHO DOESN'T LIKE UNIT TESTS! Can it be that Spolsky doesn't either?
I read the article and it could be that red flags go off in my head when I see generalities, or it could be because I was at a seminar on project management last week, or it could be that my outlook on things has changed in my old age, but I couldn't help but think of all the hidden assumptions.

Unit Tests

So, why do people write unit tests? What's the point? Are they just wasting their time? I mean, it's writing twice the code for the same functionality, right? Not quite. People write unit tests because unit tests are a useful tool that helps them accomplish one of their goals: to write reliable, maintainable software. How do unit tests obtain this? By having tests that show that the code does what it's supposed to do, they have confidence that the code continues to do what it should as changes are introduced because they can simply run the test suite to verify. And when tests that previously worked fail, they know they've introduced a bug in their changes and can quickly isolate and fix it.

The Test Driven Development (TDD) and Behavior Driven Development (BDD) people have brought these ideas to the front of the development cycle. If tests give you confidence in your code, why not write them first? Then as you develop your software, you can always and from the beginning have confidence that it does what it's supposed to do. The main difference between TDD and BDD is that with BDD the "tests" are expressed more in the language of the customer's problem domain than the language of the programmer. And thus there's more programmatic scaffolding to interpret the "tests". But the basic mechanisms are the same.

[It seems to me though that you had better pay really close attention to your design to avoid code churn where you may repeatedly write tests, then write implementations, but later delete both because that code ultimately didn't fit into your design. Sometimes you have to write code to vet aspects of a design before you know that's the design you're going to go with. This exploratory programming doesn't need tests up front IMHO]

In any case, at the end of the software project you have 2 sets of software: the software that you're going to provide to your customer and a set of unit tests that prove (to yourself and other programmers but not necessarily the customer) that the software does the things that it is supposed to do.

This is very similar to how scientific advancements are made. A scientist performs an experiment that gives some novel result. Then he publishes how he did it so that other scientists may reproduce his work. If others can not reproduce his work, then there may be something fishy going on or maybe the experiment was flawed in some way. If other people can reproduce his work, then our confidence in the validity of the experiment and its result grows. Unit tests are experimental proof that the software does what it is supposed to do (at least with regard to the things that are expressed as unit tests).

That's also why you find that code coverage tools are popular with people who write tests for their software. The tests may not exercise every bit of code in the system and a code coverage tool tells which subroutines or expressions or statements are executed. The more code that's exercised when running the tests, the more confidence that the entire software is operating as it should.

Having many unit tests that execute a high percentage of the code add up to show that statistically, the software performs as expected.

On Heroes

Spolsky's hero from the article is Jamie Zawinski (of xemacs and netscape fame) and is actually quoted as saying (in regards to unit tests) "Given a leisurely development pace, that’s certainly the way to go." So it's not so much that he doesn't like unit tests, as that he doesn't like unit tests for a particular type of development: get it out the door quick before the deadline.

But that's also a very short-sighted view of software development.

Does the programmer's obligation to the software end upon delivery to the customer? Sometimes. If, like Jamie Zawinski, your job is to get the product out *now*. Before the next guy. Before you're obsolete. Before the deadline that the sales people gave the client. Then, yes. Or if you're a mercenary programmer, it certainly does. You write some software that does a task, you give it to the customer and you're done. You're out of there. You're on to the next customer.

However, if you're not a mercenary programmer, then you're probably more interested in developing relationships. Sometimes it's a relationship with your customers; as when you develop a custom application for a customer and continue performing enhancements and upgrades long after you've delivered the initial product. Sometimes it's a relationship with your software; as when you're working on a software product that you wish to sell to the masses. Either way, you will invest more time and energy revisiting programs you've written in the past.

If you're a hot-shot programmer (HSP), you can write perfect code. You don't need tests because you're so meticulous and careful and just plain good at programming that you quickly find bugs and squash them. That's just how you do things. Jamie Zawinski is probably one of these people. Donald Knuth is famously one of these people. He is so confident in the perfection of his work (whether code or print) that he gives out monetary rewards that double as each bug is found.

And that's fine ... if you believe that HSPs are infallible and if the only programmer who will ever touch the code is an HSP or if all of the programmers that ever touch the code are HSPs. From the point of view of an HSP it doesn't matter if anyone else touches the code. Because as an HSP, you know that if you touch the code, all will be made well. But that's often not reality. Reality is that there are probably different programmers of varying skill that will ultimately touch the code over its lifetime.

From the point of view of the company that employs the HSP, they would be taking a risk not having some form of code verification as changes are introduced. Because from the employer's stand point, that HSP might be the only one on the team so other non-HSPs will definitely touch the code and they won't be as meticulous or careful. The HSP might not work at the company forever, and when he leaves, who's to say that the next guy the company hires will be an HSP or not? Odds are fairly good that he (or she) won't be. See Truck Number or Bus Number for more details on the risks involved.

Tools like unit tests help mitigate against some of these risks by codifying the correctness of the software into a test suite that can be run at any time by anyone.

On Context

These are some of the things that went through my head, but all of this is probably tangential to the point of Spolsky's article which really seems like a reaction against those people that have taken some good ideas and turned them into some sort of religion. People that latch on to the latest set of buzz-word technology and apply it everywhere. People that think that units tests are more important than the software they test. (If you're one of these people, tell me, which does the customer want?)

Spolsky praises Zawinski for his Worse is Better approach. I do too. Because it's very pragmatic. Write something useful, then let people use it. It may not be perfect, but you can iteratively refine it as needed. And do you refine it until perfection? Hell no! The perfect is the enemy of the good. Voltaire knew this 230-something years ago. Perfection is a chimera that leads you madness. The point is to just get useful things. So, you do the simplest thing possible to make the software more useful and that's it. Stop trying to predict the future. You can't. Stop trying to design for things that you imagine will be useful. Only design/write things that are actually useful now.

Oddly, these are the same ideas I hear from the practitioners of agile software development. The only problem is that when you name something, you can't be sure the name will mean what you want it to mean. I think these days when people say "agile", what's heard is "the Agile religion" rather than "that bunch of useful ideas".

Conclusion

So, with regard to unit tests ... a man with two clocks never knows what time it is, but a man with thousands of clocks invokes the law of large numbers and has a good statistical chance of knowing the time within a sufficiently small epsilon. (I hope everyone can draw the analogy :-) And if you're that man with thousands of clocks, don't get caught up in making clocks for the sake of making clocks.

Ultimately, who cares if Spolsky or Zawinski or I like or don't like unit tests? At the end of the day, to be a good developer or development company you have to find out what works for you or your team for a particular problem. Sometimes that might involve unit tests; sometimes that might mean you're a mercenary programmer; sometimes that might mean you're doing TDD. Or maybe something else entirely. Use what works.

And that's all I have to say about that. :-)

Monday, September 7, 2009

Things I wish were different in Padre

I've been using Padre as my primary editor for the last several days and I have to say that it's awesome. I've thoroughly enjoyed using it. However, there are some small things that tend to annoy so I thought I'd at least write them down so that, if nothing else, I'll have a list of potential things to hack into Padre if the mood takes me. And I'm making the list public in this way so that maybe even the LazyWeb will do the work for me :-)

In no particular order ...
  • The find dialog box appears right in the middle of the window and I always have to move it out of the way to see the text underneath. I think something like Firefox's find-at-the-bottom status bar would work well instead.

  • The mechanism for changing what language Padre thinks the document is written in is a little bit too cumbersome. There are times when I'm looking at some random perl file, but Padre doesn't figure out that it's Perl. So I have to go View -> View Document As -> and then select the appropriate language. I'd like something a little more Textmate-ish where I can click on the text in the status bar that indicates the language of the document and be able to select from the list there.

  • I wish there were a keystroke for deleting an entire line. There may actually be one, but I don't know what it is and I can't seem to find it.

  • The documentation could use a little work. :-) In searching for keystrokes that might delete a line, I stumbled across Control-D which apparently duplicates the current line. Later I was looking through the help and came across this:
    (TODO What is Ctrl-D ?, duplicate the current line?)

  • I can't seem to copy from the DocBrowser

  • DocBrowser Search doesn't seem to do anything useful as everything I search for ends in "no results found for ..."

  • Not really a Padre problem, but the vi plugin doesn't seem to support many editing keystrokes that I use all the time. I've been using Padre with the vi plugin turned off because of this, but I really wish one of two things would come to pass:
    1. the vi plugin supported more of the keystrokes I tend to use in vi or
    2. Padre provides some keystrokes of its own to do the things that I tend to want to do (like delete an entire line).
    Using Padre for the past week or so has made me realize that I'm not so tied to vi as I often think I am and that I could be happy with #2

  • There have been times when I'm clicking through a directory structure and the ".." entry at the top disappears. I'm not sure exactly when it happens, but it seems to happen whenever I click into a Catalyst project directory. I have to change the listing mode view to "navigate" to get it back and be able to navigate to the parent dir.

  • I really wish that padre would background itself when run from the command line. And that padre . would start the directory browser in the current directory.



Okay ... enough of that. These are just the little things that I've run across; nothing major. But it's the little things that affect your quality of life. Right now Padre is awesome but could use a few small QoL adjustments to make me happier.

CPAN.pm weirdness

The other day something strange happened. I tried azawawi's one-liner for upgrading Padre on my linux desktop. What happened was that the latest Padre (0.45) was downloaded and installed, but then so was version 0.40. I didn't realize that this had happened immediately, but once the upgrade was finished, I wanted to see something different, so I fired up Padre and went to Help -> About. I was shocked to see "Padre 0.40". So then I typed padre --version on the command line and again, it told me "Perl Application Development and Refactoring Environment 0.40". Still disbelieving, I asked on #padre how to tell the version of Padre installed and they, of course, said padre --version.

It was at this point that I realized I still had the window history available in the window I had typed the command originally. I scrolled back through the CPAN.pm output and there it was, plain as day; first in the original upgrade list was Padre 0.45 to upgrade Padre itself and then Padre 0.40 to upgrade Padre::Wx::Menu::Experimental (whatever that is). Weird. So, I ran the one-liner again while paying close attention to the output this time. This time it installed Padre 0.45 as expected ... and then installed Padre 0.44 because of Padre::Plugin::Perl5.

I don't know what was going on, but perhaps it was an old version of CPAN.pm because when I ran the same one-liner on my laptop, it worked flawlessly (I'll have to check the desktop tomorrow as it's at work and I'm not :). I have had weirdness before on my desktop since it was where I first installed Padre almost a year ago, so maybe that factored in somehow too. Anyway, in the end I just installed Padre 0.45 specifically and only and that worked just fine.

Monday, August 24, 2009

A Random Walk

Today I wandered around Perl6 stuff just a little bit. Here's some things that I ran into:

use.perl


First stop, masak's journal entry at use.perl. He's building a persistence layer for Web.pm that mimic's Ruby's ActiveRecord in a very simple way. Quite cool.

Drawing Blanks



Recently Rakudo Perl was changed so that make install could work. Actually, it was changed so that, in order to run the perl6 binary anywhere other than the build directory, you must run make install. Anyway, someone updated the page describing how to get Rakudo to include the make install instructions. Only they actually typed $make install where all of the other command-line-like lines have a space after the dollar sign and before the command. For some reason that little inconsistency was bugging me, so I thought, "I've got a login and edit rights, I'll just go change it!" The only problem is that when I tried to login, it took me to a blank page. Then, I was poking around on rakudo.org and there were several prominent pages that all ended up blank on my browser. Bummer. I left a note to alester with a bot on IRC in hopes that he'd know what to do.

Turtles all the way down



On a lark, I tried to install Rakudo on cygwin. However, the only Windows box I have handy is actually a VirtualBox instance. So, I tried installing Rakudo on a unix environment running on a virtual Windows environment running on a unix OS. In the process I realized just how much of Parrot's build process is dependant on Perl. It got a long way before it complained about not being able to find a compiler.

Unfortunately, it didn't work. After installing parrot, it died tried to execute parrot_install/bin/parrot_config. In fact, it seemed to die executing any of the parrot binaries from within the parrot_install/bin directory. In fact, it seemed that the only time executing one of the parrot binaries worked was when they were run from the parrot build directory.

The End



And here's where it ended because I was too tired to do anything else.

Monday, August 10, 2009

Perl 6 databases

Earlier today (or perhaps yesterday by the time I get around to publishing this) Tim Bunce showed up on #perl6 and asked who wanted a commit bit to his java2perl6 project that converts Java files into Perl6. I wanted one. I've long been interested in something like DBI on Parrot, but DBI on Perl 6 is the next best thing. So, I checked out a copy of java2perl6 and started poking around.

Wait ... what?!? What does Java have to do with DBI or Perl 6? A while back, Tim Bunce posted that the JDBC made a good model for the driver interface for DBI 2, so we might as well just use it. So, that's what's happening. We're starting with the java code for JDBC and writing software to automatically convert these java files to Perl 6. And then eventually, something like DBI wil be built on top of it all. But java2perl6 is the start.

Anyway, the java2perl6 README says
See the POD in java2perl6 (in the bin directory of the distribution) for information on how to use this module.
Great. I know how to do this, I'll just type perldoc bin/java2perl6and see what it takes to get started. Never mind that I only have passing familiarity with Java, I'll figure that out later. I know Perl 6 fairly well.

Oops! Perldoc had some problems:

POD ERRORS
Hey! The above document had some coding errors, which are explained below:
Around line 104:
’=end pod EOS’ is invalid. (Stack: =begin pod)

As it turns out, java2perl6 generates some POD as part of its output.
This POD is in a here-document which apparently confuses perldoc
since the directives that are part of the output are at the start of
lines. Aha! My first contribution to the java2perl6 project: making
java2perl6 accessible via perldoc.

Okay ... now what?

The documentation in java2perl6 gives me a good overview of the command line arguments, what the program is supposed to do, and some nice examples. So, after installing the dependencies, I do the usual perl Makefile.PL && make && make test dance and everything looks okay. All tests successful. Now to attempt a conversion or two.

There's a directory called testjavas which looks to contain some java code I can try this out on, so I do:

perl -Mblib blib/script/java2perl6 -j '-classpath testjavas' ClassTest

Since I haven't installed java2perl6, I invoke it from within the build directory and pass the testjavas directory as an argument to javap. The name of the file that I'm converting to Perl 6 is ClassTest.java. The result of running the above command is that I now have a ClassTest.pm file with some Perl 6 code in it that hopefully mimics the class definition specified in ClassTest.java.

Looking at ClassTest.pm, it seems that java2perl6 doesn't generate the various data members defined in the .java file. That seems like something I could try to implement. But, as usual, I have far too little time to continue pursuing this and I'm feeling sleepy, so perhaps updating the generator is tomorrow night's task.

On a lark, I reran the above command with the --check option to see what happened and it failed specatularly because it couldn't execute a perl6 binary in my path. That seems like something that's under-documented. Also, it would probably be nice to specify a particular location for the perl6 binary rather than relying on the
path.

There seems to be a goodly amount of low-hanging fruit for participation for when I'm not so sleepy. Awesome. For now, I'm off to bed.

Tuesday, July 28, 2009

Perl 6 Documentation

There's copious amounts of documentation for Perl 6 in the form of the Synopses but sometimes it just doesn't explain things in a way that mere mortals can understand. In order to help these mortals I've created a github project for other, hopefully more approachable Perl 6 documents. This repository can be found at http://github.com/perlpilot/perl6-docs

I figure there will be 3 kinds of documents that will be useful to have:
  • Introductions
  • Tutorials
  • Quick References
Check out the README for what goes in these documents.

I've seeded the repository with the beginnings of a Perl 6 Regex quick ref and an article I wrote a while back as an introduction to Perl 6 Regex.

I haven't actually thought too much about other people contributing to the repository yet. I mainly started this because I've always got ideas kicking around for things to write about but I rarely start something. This repository gives me a place to at least start writing (I have no excuses now!). But if someone wants a commit bit, just email me at duff@pobox.com.

Also, earlier today on #perl6 we talked about various book efforts relating to Perl 6. I don't know if books on Perl 6 should also go here, but I'm certainly not opposed to it if someone wants to contribute :-)

Saturday, July 25, 2009

Small, shiny focus.

Recently, I was reading Chad Fowler's excellent book, "The Passionate Programmer" and I'd gotten to Part III: Executing. Chapter 23, "Be Where You're At" struck a chord with me. The hypothetical person in that chapter was always looking for the next thing that will advance their career instead of paying attention their job, so they tended to do mediocre work. I'm not quite like that guy, but I have noticed that my procrastination manifests itself as an inability to focus on whatever it is that I should be working on because there's always another, more interesting problem to solve. In short, I'm easily distracted by small shiny objects :)

Then I was reading PerlMonks where kiz asked a question about Perl's auto-incrementing of strings. moritz replied with a brief
exposition
of how it works in Perl 6.

That post reminded me of one of the small contributions I made to Perl 6. I wrote some code to implement the Perl 6 semantics of string increment for Rakudo. That code has long since been replaced but the important thing was that at some point in the past, I was able to identify a small problem space in a language that I enjoy and did something about it. I was able to push through to a solution without being distracted by small shiny objects. (Although, I imagine that it was the shiny, distracting object for some other task that I should have been working on)

Thinking of that past contribution ignited some small desire to do that again despite the distractions in my life. Ergo, I intend on finding small perl-related things to focus on for as long as possible and then a little longer if necessary until I get to a stopping point and then I'll blog about it. Hopefully, as I exercise those neurons dealing with focus, they'll get stronger and the distractions will impinge upon my brain less.

Thursday, July 16, 2009

Euler #52

I was looking at the problems in Project Euler for things to do in Perl 6 and a few of them piqued my interest. The following is a minor adventure in implementing the solution to problem #52.

The problem is to find an integer such that twice the integer contains the same digits (obviously, in a different order) as three times the integer and the same digits as four times the integer and so on up to six times the integer. Here's the naive approach:

use v6;

my $n = 1;
loop {
my $s = (2*$n).comb.sort;
last if
$s eq (3*$n).comb.sort &&
$s eq (4*$n).comb.sort &&
$s eq (5*$n).comb.sort &&
$s eq (6*$n).comb.sort;
$n++;
}

say $n;

Some interesting things to note if you're not familiar with Perl 6:
  • there's a loop-forever construct
  • method call syntax uses a dot
  • everything is an object that you can call methods upon
See the official Perl 6 documentation for more information.

In order to check that the numbers have the same digits I needed to come up with some way to make a "signature" for each number such that numbers with the same digits have the same signature. I chose to do this by treating the numbers as a string of characters (a natural shift in thinking for Perl people), chopping up the string into a list of characters and sorting this list. For example, applying this process to the numbers "26321" and "62321" would both yield "12236", thus they have the same signature and the same digits.

To split the number into individual characters, you'd think that you would use the split subroutine and in Perl 5, you probably would. But Perl 6 has a shiny new routine called comb that acts as a counterpoint to split. In previous Perls, if you knew what you wanted to throw away from a string you would use split and if you knew what you wanted to keep, you'd use a regular expression capture (my @keep = $string =~ /\d/g). In Perl 6, split is the same, but comb is the routine of choice when you know the parts you want to keep. Given a regex, comb returns all parts of the string that match the regex. The default is to match single characters.

Like many things in Perl 6, there are both subroutine and object method forms. In the above code I use the method form of both .comb and .sort. (2*$n) gives me an integer that I then apply the .comb method to in order to turn the integer into a list of characters which I then apply the .sort method. Thus yielding an ordered list of the digits that comprise the integer in question.

But wait a second ... how can this work? If the result of using the .comb method is a list of characters and the .sort method sorts that list of characters, how can I use a string equality check on two lists? The answer is: Perl 6 magic! Because the lists are used as operands to the eq operator (a string operator), they get evaluated in string context. So, a number such as 26321 turns into the list ( '1', '2', '2', '3', '6') by .comb.sort which gets turns into "1 2 2 3 6" when evaluated as a string.

Neat, huh?

After I had coded this solution, it occurred to me that this approach could be improved. I think it was right around the time I got tired of waiting for an answer and hit Control-C to abort the run.

At some point 6*$n will be big enough that it will have more digits than 2*$n, thus making the probability that they have the same signature drop to 0. We can optimize a little by only examining those numbers where 2*$n and 6*$n have the same number of digits. How do I know how many digits they have? I could have just checked the length of each number, but I chose to use the logarithm function because I'm bent in a mathy sort of way.

The logarithm base 10 tells you how many digits are in a number. However, Perl 6's log function uses 2.718281828 (e) as its base, so I had to write a little routine that converts from base e to base 10.

Here's the improved code:

use v6;

sub log10($n) { return log($n) / log(10) }

my $mag = 1; # current power of 10
my $n = $mag; # number to start searching from
loop {
my $s = (2*$n).comb.sort;
last if
$s eq (3*$n).comb.sort &&
$s eq (4*$n).comb.sort &&
$s eq (5*$n).comb.sort &&
$s eq (6*$n).comb.sort;
$n++;
if log10(6*$n).int > log10(2*$n).int {
$mag *= 10;
$n = $mag;
}
}
say $n;

I call the .int method on the return value of my log10 routine to get the integer portion of the logarithm. If the logarithm of 6*$n is greater than the logarithm of 2*$n, then I need to skip to the next power of 10. The variable $mag keeps track of the current power of ten that I am examining.

For the curious, here's the optimized code that checks the length of each number:

use v6;

my $mag = 1; # current power of 10
my $n = $mag; # number to start searching from
loop {
my $s = (2*$n).comb.sort;
last if
$s eq (3*$n).comb.sort &&
$s eq (4*$n).comb.sort &&
$s eq (5*$n).comb.sort &&
$s eq (6*$n).comb.sort;
$n++;
if (6*$n).chars > (2*$n).chars {
$mag *= 10;
$n = $mag;
}
}
say $n;


Yes, it's simpler because I didn't need the log10 routine. But I did tell you I was bent. In Perl 6 the word "length" is outlawed because it isn't specific enough. It doesn't tell you what units you're getting. To ask, "what's the length of a string" you need to specify if you want the length in characters or bytes or graphemes or codepoints or whatever. To that end, there's now a .chars method that gives you the number of characters in a string.

Anyway ... that's a quick look at implementing problem #52 in Project Euler

Tuesday, June 2, 2009

Twitter bugs

So, I went to upload a picture of myself to twitter because I was tired of the default o_O thing. The first picture I selected was far too big, but twitter said "nice picture!" anyway. I didn't realize that my original picture was too big, but when it showed up on the site as a "perlpilot" instead of my picture, I kinda figured something went wrong. :-)

I resized the image and uploaded a properly sized picture (which uploaded just fine), but then twitter complains about the size of my picture. There's clearly some saved state that isn't read at the right time.