Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

Ovid (2709)

Ovid
  (email not shown publicly)
http://publius-ovidius.livejournal.com/
AOL IM: ovidperl (Add Buddy, Send Message)

Stuff with the Perl Foundation. A couple of patches in the Perl core. A few CPAN modules. That about sums it up.

Journal of Ovid (2709)

Tuesday November 24, 2009
06:27 AM

How To Become a Millionaire with Parrot and COBOL

Do a little research into COBOL and a few interesting things jump out at you. Some of this information is from Gartner Group and the rest can easily be verified by doing even a brief survey of the field. Taking the following bits of information:

  • 75% of the world's business data passes through COBOL (Gartner Group estimate)
  • There is possibly up to a fifth of a trillion lines of COBOL code out there (Gartner again)
  • People are still writing COBOL constantly, but usually on existing systems.
  • The industry is struggling to find new COBOL programmers because few young programmers love the thought of maintaining decades-old enterprise systems where all data is global and GOTO is often the first choice in flow control.
  • Many companies want to move from COBOL, but can't do so easily because too much code is written in COBOL (and the source is often lost).

People really, really underestimate these problems. For example, I've seen several companies express a desire to move away from Perl but find out they can't because they don't realize quite how reliant on the language they are. Now imagine a multi-national corporation with several million lines of COBOL code. What are they going to do?

COBOL salaries, from what I've seen, are trending upwards. Older programmers are sometimes being enticed out of retirement to maintain legacy systems (this is rather hit or miss as there appears to still be some age discrimination here). There are companies out there offering software to allow COBOL programmers to write NetBeans, integrate with .NET code or simply translate the COBOL into other languages (the latter appears to have mostly been a disaster, but I don't have enough hard data on this).

So let's summarize the above:

  • Trillions of dollars flow through COBOL.
  • Trillions of dollars flow through systems that businesses want to replace.
  • Current mitigation strategies involve supplementing COBOL, not replacing it.

You see the issue here? There's a fortune to be made for the people who figure out how to turn this trick. My thought is to not write supplementary tools for COBOL. It's to write a COBOL compiler on top of Parrot. Imagine coming across the following COBOL[1]:

000510 MAIN-PARA.
000520     OPEN INPUT IN-FILE
000530          OUTPUT OUT-FILE
000535
000540     PERFORM UNTIL END-OF-FILE
000550       ADD 10 TO LINE-NUMBER
000560       READ IN-FILE AT END
000570         MOVE 'Y' TO EOF-FLAG
000580       NOT AT END
000590         IF     (CHAR-1 = '*')
000600                  OR (CHAR-1 = '/')
000610                  OR (CHAR-1 = '-') THEN
000620            MOVE LINE-CODE-IN TO L-COMMENT
000630            MOVE LINE-NUMBER TO L-NUM-COM
000640            WRITE LINE-CODE-OUT FROM NUMBER-COMMENT
000660         ELSE
000670            MOVE LINE-CODE-IN TO L-CODE
000680            MOVE LINE-NUMBER TO L-NUM-CODE
000690            WRITE LINE-CODE-OUT FROM NUMBER-CODE
000720         END-IF
000730       END-READ
000740       INITIALIZE NUMBER-CODE NUMBER-COMMENT
000750     END-PERFORM

With Parrot and a COBOL compiler, you could allow a more modern langauge (say, Rakudo) to be embedded:

000510 MAIN-PARA.
000520     OPEN INPUT IN-FILE
000530          OUTPUT OUT-FILE
000535
000540+Rakudo
       my $line_num = 0;
       while <C:IN-FILE> {
           $line_num += 10;
           my $c_area = /^[-*/]/ ?? '' !! ' '; # is this a comment?
           print C:OUT_FILE sprintf "%06d$c_area%-100s" => $lin_num, $line;
       }
000550

Now this example isn't the greatest (but being able to declare the variables next to where they're used is a huge win), but imagine working with free-form text. I once took a huge bit of COBOL translating CSV data to a fixed-width format and got it down to 10 lines of Perl (with error checking). With this strategy, you could gradually migrate away from COBOL by embedding a modern language directly inside the COBOL instead of keeping the COBOL and wrapping modern tools around it.

I'm surprised I've never seen this approach before. It really shouldn't be too hard. (If anyone wants to pay me a bazillion dollars to do this, let me know :)

1. If you look carefully at the COBOL and the Perl 6, you have no way of knowing if they're functionally equivalent due to how COBOL variables are declared. In fact, if you don't know COBOL, you might be misled into thinking that the COBOL code can't possibly be correct (look at the variable names), but it is.

Monday November 23, 2009
08:56 AM

How Not To Advertise Your Job Service

From the front page of getcoboljobs.com:

"I've used the service for some weeks now and even though I haven't had an offer from anyone yet, I'll keep using the service. Thanks for providing it." - Michael Mayes, Mainframe Developer Analyst

Yeah, that would make me rush right out and sign up! (Does just getting close to COBOL make you stupid?)

06:40 AM

Hash Objects and AutoInflation

Until the issues are sorted out with blogs.perl.org, I'll still be posting here for a while (probably cross-posting for a while after, too).

Recently I've wanted a simple hash object:

my $object = Hash::Object->new({
  id   => $some_id,
  this => 'that',
  name => 'john',
});

print $object->name; # john

The problem is that current implementations I've found have limitations. One uses AUTOLOAD so any method name becomes valid. Another doesn't do that, but it also does nothing else. I'd like to be able to autoinflate an object such that if I call an unknown method, it inflates the hash object into a full-blown object and redispatches to that object, only displaying a "Can't locate object method" error if the "inflated" version of that object doesn't provide the requested method.

my $object = Hash::Object->new(
  data => {
    id   => $some_id,
    this => 'that',
    name => 'john',
  },
  inflate => sub { Customer->find({ id => shift->id }) }
);

print $object->name;

# inflates to full Customer object and redispatches method
print $object->fullname;

The reason for this is that we sometimes have very expensive objects, but we only need one or two pieces of data from them. It would be nice to return a "proxy" object, containing the data we probably want, but will transparently work like the real thing if needed.

This is on the CPAN, yes? What's it called?

Friday November 20, 2009
04:03 AM

blogs.perl.org

It's official! We've a new blogging site available for the Perl community. Dave Cross has now made the announcement. I've a blog post over there explaining a few things about it. It's still alpha and there will be bugs, so keep that in mind. That being said, play around and have fun.

Tuesday November 17, 2009
06:24 AM

Why no plan for nested TAP?

At least one person has objected quite strongly to my patch for Test::Builder which adds an implicit done_testing() to subtests with no plan. I was kind of surprised with the vehemence of the discussion, so I want to clear this up.Consider the following test subtests:

subtest 'with plan' => sub {
    plan => 2;
    is $this, $that, 'this is that';
    is $foo,  $bar,  'foo is bar';
};

subtest 'without plan' => sub {
    is $this, $that, 'this is that';
    is $foo,  $bar,  'foo is bar';
};

Now imagine that this is a test suite you're currently working on and you keep adding tests to each. It will be annoying to keep updating the plan and sometimes get spurious test failures when your code is fine. The "without plan" subtest is much easier to use. If you want plans in your subtests, fine! Use them. There's nothing stopping you, but if you forget, I've added a safety net. Don't sweat it and have fun.

Unlike with the overall test program, you know exactly when that subtest ends. The plan buys you virtually nothing. In a subtest, instead of an annoyance which actually helps, it's an annoyance which hinders. Heck, for my top level tests, I'm thinking about writing a vim macro which automatically inserts this:

use Test::Most;  END { done_testing() }

Plans are almost not needed any more (this isn't entirely true, but for subtests, why bother?). I'm hard-pressed to believe that they now add enough value to overcome the annoyance of using them.

Sunday November 15, 2009
02:25 PM

The Obligatory Go Language Post

So I've been checking out Google's new "Go" language. There's an interesting example at the Go tutorial. Specifically, the following code is a simple very of "echo".

package main

import (
    "os";
    "flag"; // command line option parser
)

var omitNewLine = flag.Bool("n", false, "don't print final newline");

const (
    Space   = " ";
    Newline = "\n";
)

func main() {
    flag.Parse();
    s := "";
    for i := 0; i < flag.NArg(); i++ {
        if i > 0 {
            s += Space;
        }
        s += flag.Arg(i);
    }
    if !*omitNewLine {
        s += Newline
    }
    os.Stdout.WriteString(s);
}

Basically, it checks your leading options for the presence of an "-n" switch and, if present, does not emit a trailing new line. Other than that, it prints the arguments to the program, separated by spaces. It might seem rather verbose, but you have to remember that Google envisions this as a systems language. Note that you don't have to reallocate anything for the "s" variable as Go handles that for you. Trying to dynamically resize strings in C leads to fun bugs, but you don't have to do that here. Go takes care of memory management for you.

You might have noticed the var s string = ""; line. Go doesn't support type inference, but it has a simplified version for variable declaration. In the above, you could omit the "string" keyword, or just use the ":=" operator and declare and assign in one fell swoop:

var s string = "";
var s = "";   // go knows you wanted a string
s := "";      // same thing

Unlike some dynamic languages, declaration and assignment are clearly separate, making it easy to put proper scoping semantics into the language (though I haven't really checked out how they handle scoping yet) and avoiding silly issues where you think you're assigning to a variable but you've mistyped the name and you're also declaring it.

I'm also intrigued by their lack of a type hierarchy in favor of interfaces. In short, you don't get inheritance. Going with interfaces seems a poor choice because you still have the reimplementation problem, but I'm curious to see what will become of this. Dr. Michele Simionato has an interesting blog entry discussing his initial surprise at being introduced to objects. His background is mathematical in nature and he just didn't understand the need for type hierarchies.

Another interesting bit about Go is that you can't do pointer math wrong. That's because they have pointers, but no pointer math. Kind of like references in Perl, eh? Seems an obvious step.

I'll play more with Go as I have time, but it's beginning to look like there are some interesting ideas for a systems language. I'm curious to know if the lack of full-blown type inference was a deliberate design decision to ensure that the developer can see what's happening at every step of the way, except for the common cases where it's frickin' obvious (such as assigning an int to a variable).

08:03 AM

Vim: Automatically opening POD as a PDF

Doing a bit of POD munging and using Pod::Parser::Groffmom with this. The following is OS X specific, but it should be easy to adjust for another system. It automatically opens any POD file as a PDF document with cover page and table of contents:

au! FileType pod           :call PodMappings()

function! PodMappings()
    noremap <buffer> ,r :call PodToPDF()<cr>
endfunction

function! PodToPDF()
    let filename   = bufname("%")
    let postscript = filename . ".ps"
    let command  = 'perl $(which pod2mom) --cover --toc --ps '
        \ . filename
        \ . ' && open ' . postscript
    echo system(command)
endfunction

Saturday November 14, 2009
05:25 AM

Vim: Does Your Pod Have Valid Perl?

After writing some vim code to run your POD code, I realized I needed another snippet to simply tell me if my POD code compiled (without running it). The vim mapping:

vnoremap <silent> <leader>c :!perl ~/bin/validperl<cr>

Select a region of Perl code, hit ",c" (or whatever your leader is) and if no compilation errors are detected, you'll see no change. Otherwise, they will be added after an "__END__" token. Here's the code for validperl:

#!/usr/bin/env perl

use strict;
use warnings;
use File::Temp 'tempfile';

my $tmpdir = '/var/tmp';

my ( $fh, $snippet ) = tempfile(
    'eval_XXXX',
    SUFFIX => '.pl',
    DIR    => $tmpdir,
);
my $code = do { local $/; <STDIN> };
print $fh $code or die "Could not print code to ($snippet): $!";
close $fh or die "Could not close ($snippet): $!";

my $perl = $^X;
print $code;
my $output = qx{ $perl -Ilib -c $snippet 2>&1 };
exit if $output =~ m{^$tmpdir/eval_\w+.pl syntax OK$};
$output =~ s/\n/\n /g;
print " __END__\n $output";

Friday November 13, 2009
12:21 PM

Implicit "done_testing()" in subtests

Per a previous blog entry, I've submitted a pull request on github to implement an implicit done_testing() on subtests with no plan. This is due to the following:

subtest 'trim' => sub {
    plan tests => 2;
    # snip
};

subtest 'escape' => sub {
    plan tests => 2;
    # snip
};

subtest 'interior sequences' => sub {
    plan tests => 6;
    # snip
};

It was getting awfully annoying having to maintain plans for all of the subtests when I could clearly distinguish when a subtest was finished. If the pull request is accepted, you can just do this:

subtest 'some subtest' => sub {
    isa_ok my $cust = Customer->new({
      given  => 'John',
      family => 'Public' }
    ), 'Customer';
    can_ok $cust, 'given';
    is $cust->given, 'John',

    can_ok $cust, 'family';
    is $cust->family, 'Public';
};

done_testing() will be implicitly called at the end of that (and you can list it explicitly, if you want). This allows you to safely add extra tests to all subtests without worrying about the plan, nor do you have to worry about annoying plan management unless it's really important.

02:22 AM

The new perl.org is up!

perl.org actually looks modern now! This has been in the works for a while now and, as far as I know, Leo Lapworth was the principle designer. And no, this was not a result of the marketing committee. Just another great volunteer who wanted to make Perl not look dead :)

There are other nice things to come, too. I'm really looking forward to some of the changes which are occurring in the Perl community.

Update: Apparently, Foxtons is responsible for sponsoring this work. For those outside the UK: Foxtons, from what I understand, is one of the largest estate agents in the UK. Apparently, they got there by being very innovative and investing in a top-notch IT department. An IT department which, not surprisingly, uses a lot of Perl :)