btilly's Friends' Journals btilly's Friends' use Perl Journals en-us use Perl; is Copyright 1998-2006, Chris Nandor. Stories, comments, journals, and other submissions posted on use Perl; are Copyright their respective owners. 2012-01-25T02:08:56+00:00 pudge Technology hourly 1 1970-01-01T00:00+00:00 btilly's Friends' Journals Bob Jacobsen interview on FLOSS Weekly Last week, I interviewed Bob Jacobsen for FLOSS Weekly. Bob used Perl's Artistic 1.0 license on some Java code to manage model trains. The code was later patented by an Oregon-based company(!) and then Bob got sued(!!) for Bob distributing the other company's patented code(!!!). The good part of the story is that this is the first test at the US Federal Appeals Court level for an open source license to be enforceable even if no money exchanges hands, and... we won! <p> Bob spent a lot of time and money on the case though. Listen to <a href="">the podcast</a> and contribute to <a href="">his legal defense</a> if you care about open source.</p> merlyn 2010-04-23T03:55:11+00:00 journal Gone <p>Like many others, I'm no longer posting here very much. You'll find my new technical journal at <a href=""></a>. It's much shinier.</p><p> <a href="">As you can see, use.perl visits have been dropping for a while</a> ( is too new to show up on that search) and the <a href="">front page of use.perl has been sadly neglected</a>. As for, after an initial rough start, <a href="">plenty</a> <a href="">of</a> <a href="">people</a> are switching over and are very happy with the shiny.</p><p>I have fond memories of, but it's just too old and out-of-date. Come on over to our new platform and look around. Plus, <a href="">tell us what you want changed about it</a>. (To be fair, while I was involved in the project to get it launched (mostly kibitzing and asking why things were stalled -- I'm such a marketroid<nobr> <wbr></nobr>:), the hands-on work was Dave Cross, Aaron Crane and the wonderful folks at <a href="">SixApart</a>.)</p> Ovid 2010-03-14T08:02:43+00:00 journal Test::Class::Most <a href="">Test::Class::Most</a>. Ovid 2010-01-31T19:25:10+00:00 journal Testing with PostgreSQL <p>My new personal project has a PostgreSQL database. <a href="">Here's how I'm handling testing</a>.</p> Ovid 2010-01-30T16:22:57+00:00 journal Roles without Moose? <p> <a href="">Milliseconds are important</a>.</p> Ovid 2010-01-25T14:04:31+00:00 journal Unless what? <p> <a href="">Unless what?</a> </p> Ovid 2010-01-15T11:47:53+00:00 journal Dear Recruiters <p> <a href="">Dear Recruiters</a> </p> Ovid 2010-01-13T13:06:11+00:00 journal Next QA Hackathon -- What Do You Need? <p> <a href="">Read about the next QA Hackathon</a>.</p> Ovid 2010-01-12T11:37:14+00:00 journal Most Popular Testing Modules - January 2010 <p> <a href="">Most popular testing modules as of January 2010</a> </p> Ovid 2010-01-07T21:46:46+00:00 journal Cool Things in Perl 6: Subsets <p> <a href="">They're going to be a lot of fun</a>.</p> Ovid 2010-01-04T13:11:31+00:00 journal Perl 6 Config::INI parser on github <p> <a href="">Details here</a>.</p> Ovid 2009-12-30T17:48:47+00:00 journal Improve My Perl 6! <p> <a href="">Collaborative filtering (user recommendations) in Perl 6</a>.</p> Ovid 2009-12-24T11:29:45+00:00 journal Gitpan languages <p>What? You didn't know that <a href="">SOAP::Lite was written in Visual Basic</a>?</p> Ovid 2009-12-18T14:15:32+00:00 journal Atom Feed Help <p> <a href="">Atom feed help requested</a> </p> Ovid 2009-12-17T10:40:35+00:00 journal MySQL and Oracle <p> <a href="">MySQL and Oracle</a>. (Despite teething pains, is holding up quite well on the new server)</p> Ovid 2009-12-14T12:56:02+00:00 journal What's In A Name? <p> <a href="">The actual entry is at</a>. However, here's a few extra notes about that site:</p><p>It's much more stable than last time. Aaron moved it to a new server and Dave set up MT. <a href="">The templates are on github</a> along with <a href="">an issue tracker</a>.</p><p>Barbie talked with Dave and myself at the London Perl Workshop (lpw2009) about the site and I wrote down all of his suggestions and they've now been added to the issue list. We look forward to more people trying it out and <a href="">Dave has a post asking for more feedback</a>. Also, he's aware that several people only made it partway through the registration process. Drop him a line if you're affected and he'll clear it up for you.</p><p>I can't thank Dave, Aaron and SixApart for all they're doing to create a modern blogging platform for us.</p> Ovid 2009-12-12T12:24:54+00:00 journal Regex Captures in Debugger <p>Stumbled across this weird behavior today. Took a while to debug it. In the debugger, I'm not seeing the "dollar digit" regex capture variables set, even though the regex matches.</p><blockquote><div><p> <tt>$ perl -de 1<br> <br>Loading DB routines from version 1.3<br>Editor support available.<br> <br>Enter h or `h h' for help, or `man perldebug' for more help.<br> <br>main::(-e:1):&nbsp; &nbsp;1<br>&nbsp; DB&lt;1&gt; ($foo) = ('abcd' =~<nobr> <wbr></nobr>/(bc)/)<br> <br>&nbsp; DB&lt;2&gt; x $1<br>0&nbsp; undef<br>&nbsp; DB&lt;3&gt; x $foo<br>0&nbsp; 'bc'</tt></p></div> </blockquote><p>Is this documented? I can't find it.</p><p> <strong>Update</strong>: Rafael explained it. The digit variables are lexically scoped. That's why you can assign to a package variable in a debugger, but not a lexical.</p><blockquote><div><p> <tt>&nbsp; DB&lt;6&gt;&nbsp; 'abcd' =~<nobr> <wbr></nobr>/(bc)/ &amp;&amp; print $1<br>bc</tt></p></div> </blockquote> Ovid 2009-12-08T14:02:43+00:00 journal The Implications of the Bug <p> <a href="">mscolly</a> correctly identified <a href="">the SQL bug I posted</a>. Sadly, no one discussed the implications of this bug and I think they're the most interesting part of this. Essentially, it comes down to the following:</p><blockquote><div><p> <tt>SELECT&nbsp; &nbsp; first_name,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; last_name,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; order_date,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SUM(price) AS total&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -- what if there's no price?<br>FROM&nbsp; &nbsp; &nbsp; customer<br>LEFT JOIN orders&nbsp; &nbsp; &nbsp;ON = orders.customer_id<br>LEFT JOIN order_item ON; &nbsp;= order_item.order_id<br>GROUP BY&nbsp; first_name, last_name, order_date<br>HAVING&nbsp; &nbsp; total &lt; 15&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;--&nbsp; what does NULL &lt; 15 evalute to?<br>ORDER&nbsp; &nbsp; &nbsp;BY order_date ASC;</tt></p></div> </blockquote><p>The proper solution (as mscolly pointed out) is to change the "SUM" line to this:</p><blockquote><div><p> <tt>COALESCE( SUM(price), 0 ) AS total</tt></p></div> </blockquote><p>The English language, as we know, is ambiguous. If you boss had come in and asked for all customers whose orders (more accurately, whose orders with order items) totaled less than &#163;15 pounds, then the above query would have actually been correct, but another programmer coming along to maintain it could be forgiven for thinking it's in error. If you ever write SQL which is likely to produce NULLs (e.g., outer joins), you should explicitly handle that case if you actually do anything with those NULLs.</p><p>But in this case, "customers whose orders total less than &#163;15" is significantly different in meaning than "customers who spent less than &#163;15" and the latter is what we want, but the former is what we have. While the above code <em>seems</em> logical, it gives a logically incorrect answer because it omits customers without orders (or order items), even though they're clearly intended. However, NULLs make it very difficult to identify what you actually mean because the database can't know why something is NULL.</p><p>Now consider a simpler, yet silly, example:</p><blockquote><div><p> <tt>SELECT first_name<br>FROM&nbsp; &nbsp;employee<br>WHERE&nbsp; salary &gt; 50000;</tt></p></div> </blockquote><p>What happens if the <tt>salary</tt> field is NULL? You'll get a list of employees whose <em>known</em> salary is NOT NULL. Why might they not have a salary? Maybe they're an hourly employee and the <tt>salary</tt> field is not applicable. Maybe they're the CEO and he doesn't think you need to know his salary. Maybe they're an ex-employee and they have no salary.</p><p>Taking this a bit further, imagine that all employees in the table are current and all have salaries (no hourly workers), but the <tt>salary</tt> field is still sometimes NULL because the board of directors doesn't want you to know their salaries. With me so far? In this scenario, it is the case that everyone has a salary; you just don't know what some of them are. So here's the kicker:</p><blockquote><div><p> <tt>SELECT first_name<br>FROM&nbsp; &nbsp;employee<br>WHERE&nbsp; salary = salary;</tt></p></div> </blockquote><p>That won't return anyone on the board of directors, even though you <em>know</em> they have a salary. Furthermore, most would think it's self-evident that <em>p&nbsp;=&nbsp;p</em>, but in three value logic of databases, this is sometimes true and sometimes false. Heck, because of this, the following does not always evaluate correctly, even though we would <em>think</em> it does:</p><blockquote><div><p> <tt>SELECT service_id,<br>&nbsp; &nbsp; CASE WHEN master_brand_id =&nbsp; master_brand_id THEN '='<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;WHEN master_brand_id != master_brand_id THEN '!='<br>&nbsp; &nbsp; END AS 'comparison'<br>FROM service</tt></p></div> </blockquote><p>Sure, you say, but you're comparing something to itself. You don't do that in the real world. No? So look at this:</p><blockquote><div><p> <tt>SELECT s.service_id,<br>&nbsp; &nbsp; CASE WHEN m.master_brand_id =&nbsp; s.master_brand_id THEN '='<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;WHEN m.master_brand_id != s.master_brand_id THEN '!='<br>&nbsp; &nbsp; END AS 'comparison'<br>FROM service&nbsp; &nbsp; &nbsp; s<br>&nbsp; &nbsp; &nbsp;master_brand m</tt></p></div> </blockquote><p>If the <tt>s.master_brand_id</tt> is allowed to be NULL, than the <tt>comparison</tt> field will always have a NULL value when <tt>s.master_brand_id</tt> is NULL. It's easy to debug in this simple example, but what if that was a subquery? It <em>looks</em> fine, but it all breaks down in the presence of NULL values.</p><p>I didn't start with that example because people would say it's silly, but starting with the "order" example shows how NULLs in databases can return logically incorrect data and the reduction down to the simple <em>p&nbsp;=&nbsp;p</em> case not holding shows why this happens.</p><p>At this point, I can see people saying "yeah, but we already know that about databases." And this is true. It's well-known that certain types of queries can generate NULLs even though there are no NULL values in the database. Regrettably, many people assume the database logic is, well, logical. The <em>p = p</em> failure is a strong rebuttal, but I suppose some people assume that hitting themselves in the head with a hammer is normal.</p><p>If you really want to have some fun, <a href="">read this blog entry about NULL values</a>. In the comments, the author even explains how to deal with NULLs in outer joins, but it requires a relational database (very few databases really are) and that people understand what first normal form is really about. (If you think you know, please define "atomic values" in the comments below).</p><p>I wonder how database design would look today if, instead of 3VL, databases threw an exception when you tried to apply an operator or aggregation ('=', '+', 'SUM', etc.) to NULL values?</p><p>Note: I've discussed <a href="">the problem with NULL values before</a>, but in realizing I had a better real-world example, I thought it would make more sense to readers.</p> Ovid 2009-12-07T15:38:13+00:00 journal Find the bug (sql) <p> <strong>Update</strong>: You can ignore the <tt>order_date</tt> below. It's a red herring and I probably should have left it out, but I had liked the fact that by putting it in the query, I added more complexity, thus making the real bug more difficult to spot.</p><p>Assume you're a diligent programmer. You've designed your database carefully. Foreign constraints are correct, you have no null columns and you've kept a nice, simple design. Now your boss wants you to provide a list of all customers who've spent less than &#163;15 on your Web site because you want to offer them a special promotion. Here's the SQL you've written:</p><blockquote><div><p> <tt>SELECT&nbsp; &nbsp; first_name,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; last_name,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; order_date,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SUM(price) AS total<br>FROM&nbsp; &nbsp; &nbsp; customer<br>LEFT JOIN orders&nbsp; &nbsp; &nbsp;ON = orders.customer_id<br>LEFT JOIN order_item ON; &nbsp;= order_item.order_id<br>GROUP BY&nbsp; first_name, last_name, order_date<br>HAVING&nbsp; &nbsp; total &lt; 15<br>ORDER&nbsp; &nbsp; &nbsp;BY order_date ASC;</tt></p></div> </blockquote><p>The two left joins are there because a customer may never have placed an order before. Heck, they may have started an order but not added any items to it. The 'having' statement is required because you generally can't use aggregates in where clauses.</p><p>You run the SQL and hand-check the results very carefully. Choosing a random sampling of customers returned, you verify that none of them have spent more than &#163;15 on your site. Nonetheless, you have a bug. What is it? What are the implications of the bug?</p> Ovid 2009-12-07T07:43:40+00:00 journal Pitfalls in Converting Base Classes to Roles <p>I should have responded to this a while ago, but didn't. Basically, nothingmuch <a href="">has a blog post responding to some of my comments about roles</a> and it's worth reading. However, there's one problematic bit:</p><p><div class="quote"><p>If you take a working multiple inheritance based design and change every base class into a role, it will still work. Roles will produce errors for ambiguities, but if the design makes sense there shouldn't be many of those to begin with. The fundamental structure of the code hasn't actually changed with the migration to roles.</p></div><p>For the majority of code bases I see, this is doubtless true. However, I tend to get jobs where I work on large code bases. For example, just looking at our lib/ directory:</p><blockquote><div><p> <tt>$ find lib/ -name '*.pm' | wc -l<br>652</tt></p></div> </blockquote><p>That's not huge, but it's not particularly small, either. And it doesn't count our various scripts, tests, schemas, etc. So let's say I want to add a boolean attribute to an object and said attribute must be persisted in the database and must be readable/writeable via our API. That's a single attribute. Just one. I need to:</p><ul> <li>Write the database migration level</li><li>Update our RelaxNG schemas</li><li>Update our data extractors (extracts data from XML docs)</li><li>Add the column to our domain objects</li><li>Add the column to our resultsource classes</li><li>Possibly add the column to resultset classes</li><li>Update our XML builders</li><li>Write tests</li><li>And possibly more, depending on why we're adding the attribute</li></ul><p>That's a lot of work, but adding a single boolean attribute can take me an hour or two if I'm not interrupted. And, believe it or not, this is easier than it used to be. And, believe it or not, much of that isn't the silly grunt work that it appears to be because there's a lot of stuff that is hard to automate away safely (my unreleased <a href=";ei=ZAcZS4HHC8-24Qbtu4nmAg&amp;sa=X&amp;oi=spell&amp;resnum=0&amp;ct=result&amp;cd=1&amp;ved=0CAYQBSgA&amp;;spell=1">Bermuda</a> project was an attempt to do this). Some can and we've managed some of it, but not all.</p><p>In short, we have a complicated code base that has decades of programmer hours in it. We used to rely a lot on multiple inheritance, despite the well-known issues with MI. Now let's revisit the key sentence in nothingmuch's post: "If you take a working multiple inheritance based design and change every base class into a role, it will still work."</p><p>To nothingmuch's credit, he does point out that ambiguities will cause errors, but there's a lot more to it than that. As projects grow organically, things often get put into incorrect spots. We had all sorts of code shoved into base classes that our derived classes shouldn't inherit from, but did. Since tests tend to be written against expectations, it's easy to not write tests for things you don't expect.</p><p>The reason classes sometimes have inappropriate behavior is because abusing inheritance tends to mean that you're having classes manage both responsibilities and cross-cutting concerns. I've found that base classes often had to be broken up into two or more roles (nothingmuch has a great example of Test::Builder doing the same thing and that's a <em>small</em> code base). That can get really annoying when you find that each role requires the same private method and you're trying to figure out where to put it. As you juggle things like this, behaviors <em>will</em> change and you had better have a good test suite to catch them.</p><p>There's another, more subtle problem. Imagine that you have the following (it gets much worse when MI is involved):</p><blockquote><div><p> <tt>AbstractParent<br>&nbsp; &nbsp; &nbsp;^<br>&nbsp; &nbsp; &nbsp;|<br>AbstractChild<br>&nbsp; &nbsp; &nbsp;^<br>&nbsp; &nbsp; &nbsp;|<br>ConcreteClass</tt></p></div> </blockquote><p>In ConcreteClass we have this:</p><blockquote><div><p> <tt>sub clean_the_kitchen {<br>&nbsp; &nbsp; my $self = shift;<br>&nbsp; &nbsp; $self-&gt;SUPER::clean_the_kitchen;<br>&nbsp; &nbsp; $self-&gt;mop_the_floor;<br>&nbsp; &nbsp; return $self;<br>}</tt></p></div> </blockquote><p>What happens with that <tt>SUPER::</tt> call? If it's only in AbstractParent, you're fine, but if it's also in AbstractChild, converting AbstractChild into a role will break your code. Further, it might break your code in very subtle ways that are hard to detect. This might seem uncommon, but we actually had this happen quite a bit when we were converting over to roles. This means that our concrete class methods needed to be written as:</p><blockquote><div><p> <tt>after 'clean_the_kitchen' =&gt; sub {<br>&nbsp; &nbsp; my $self = shift;<br>&nbsp; &nbsp; $self-&gt;mop_the_floor;<br>&nbsp; &nbsp; return $self;<br>};</tt></p></div> </blockquote><p>That's easy to get wrong and, frankly, method modifiers such as <tt>before</tt>, <tt>after</tt> and <tt>around</tt> generally make me feel uncomfortable. Like role method aliasing and excluding, they're code smells suggesting your design needs work. However, as we were trying for "the simplest thing that could possibly work", we went with this with the intent of revisiting it later. We still haven't revisited it. We have work to do.</p><p>In short, converting bases classes to roles and resolving composition errors is often enough for small code bases, but as code bases get large and complex, it's much harder. There are plenty of pitfalls and they're not always obvious. Plus, despite having excellent code coverage for tests, you probably don't have great path coverage (few do). This means that switching from base classes to roles can easily introduce behavioral changes that you haven't been expecting.</p><p>See also <a href="">Tips For Converting Base Classes Into Roles</a>. <small>(gosh, tags would be useful)</small> </p> Ovid 2009-12-04T13:32:44+00:00 journal Why Should I Program in $Language? <p>For the developer evaluating programming languages the question of which languages to learn rarely involves "can this language do what I want it to do?" This is because virtually all programming languages (except ANSI SQL, if you consider it a language) are Turing Complete. Instead, what I see, over and over, is discussions over two things:</p><ul> <li>Can I get a job in this language?</li><li>Do I like this language?</li></ul><p>So consider COBOL. Yes, I can get a job in that language, but do I like it? No. C is the same way for me. There are plenty of jobs out there, but I loathe how close it is to the metal because I like solving problems, not worrying about how to reallocate memory for a resized string. So if I were to assert that either COBOL or C is dead, that might be true<nobr> <wbr></nobr>... for me. If I assert they're dead on the basis of job stats, I'd be sorely mistaken.</p><p>Naturally, when I hear the old "Perl is dead" saw, I know the job stats and I know they're not referring to them. However, what they invariably refer to is the "buzz" around Perl, measured by TIOBE, Google Trends and other tools. The buzz can be important, but at the end of the day, buzz won't matter if the tool is useful enough. Consider how much people complain about Perl's sigils. Now look at the following code:</p><blockquote><div><p> <tt>$cssClass = "";<br>if ( $element-&gt;isOpen() ) {<br>&nbsp; &nbsp; $cssClass = ' class="selected"';<br>}<br>if ( !$element-&gt;isHiddenInNavigation() ) {<br>&nbsp; &nbsp; $filepath = $element-&gt;getId() . ".html";<br>&nbsp; &nbsp; if ( substr( $element-&gt;getFilePath(), 0, 4 ) == 'http' ) {<br>&nbsp; &nbsp; &nbsp; &nbsp; $filepath = $element-&gt;getFilePath();<br>&nbsp; &nbsp; }<br>&nbsp; &nbsp; $result<nobr> <wbr></nobr>.= '&lt;li'<br>&nbsp; &nbsp; &nbsp; . $cssClass<br>&nbsp; &nbsp; &nbsp; . '&gt;&lt;a href="'<br>&nbsp; &nbsp; &nbsp; . $filepath . '"&gt;'<br>&nbsp; &nbsp; &nbsp; . $element-&gt;getLabel() . '&lt;/a&gt;'<br>&nbsp; &nbsp; &nbsp; . $this-&gt;generate( $element-&gt;getChildren() ) . '&lt;/li&gt;';<br>}</tt></p></div> </blockquote><p>Assuming that has no errors, we know that it <em>looks</em> like Perl, but isn't (look closely if you don't see it). That's PHP code. So though people whine about sigils in Perl, you've got the same issue with PHP, but why has PHP <em>crushed</em> us in the Web space? Well, for one thing, people seem far happier with modphp than mod_perl. It's very easy to develop and deploy apps despite its inconsistencies and lacking many of the useful features that Perl 5 has.</p><p>A second issue, however, is the one which will continue to keep Perl 5 sneered at:</p><blockquote><div><p> <tt>public function setHiddenInNavigation($hideInNavigation) {<br>&nbsp; &nbsp; return $this-&gt;hideInNavigation = $hideInNavigation;<br>}</tt></p></div> </blockquote><p>That's PHP, too. Until we can make Perl 5 code that clean and simple <em>and in the core</em>[1], we'll continue to be sneered at. It's embarrassing to read through PHP code and, once again, sigh at basic, basic things Perl 5 is missing (yes, PHP is missing many things too, but I'll bet most 9 to 5 programmers would take method signatures over closures any day of the week).</p><p>So really, programmers <em>are</em> asking if a language can do what they want it to do; at least on a syntax level. That's because syntax is a large part of the aesthetic appeal of a language.</p><p>So in answer to the question "Why Should I Program in $Language?", what the language can do (functionally, not syntax!) isn't really the issue. Nor is the "are there jobs?" because we know there are plenty of Perl jobs out there (not in all areas, though). The real question is "will I like it?" and from the numerous Perl hate posts, this is very much an open question but Perl largely has itself to blame.</p><p> <small>1. We have a better object system than you do! Just install Moose (but be aware that it might have backwards-incompatible changes in a few months). Oh, to install it, you just need to configure CPAN. What? You don't have root? Here's how to configure CPAN to install in a local directory. And be aware that Module::Build and ExtUtil::MakeMaker take different arguments, and don't forget that<nobr> <wbr></nobr>...</small> </p> Ovid 2009-12-01T14:27:17+00:00 journal How To Become a Millionaire with Parrot and COBOL <p>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:</p><ul> <li>75% of the world's business data passes through COBOL (Gartner Group estimate)</li><li>There is possibly up to a fifth of a <em>trillion</em> lines of COBOL code out there (Gartner again)</li><li>People are still writing COBOL constantly, but usually on existing systems.</li><li>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.</li><li>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).</li></ul><p>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?</p><p>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<nobr> <wbr></nobr>.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).</p><p>So let's summarize the above:</p><ul> <li>Trillions of dollars flow through COBOL.</li><li>Trillions of dollars flow through systems that businesses want to replace.</li><li>Current mitigation strategies involve supplementing COBOL, not replacing it.</li></ul><p>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]:</p><blockquote><div><p> <tt>000510 MAIN-PARA.<br>000520&nbsp; &nbsp; &nbsp;OPEN INPUT IN-FILE<br>000530&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; OUTPUT OUT-FILE<br>000535<br>000540&nbsp; &nbsp; &nbsp;PERFORM UNTIL END-OF-FILE<br>000550&nbsp; &nbsp; &nbsp; &nbsp;ADD 10 TO LINE-NUMBER<br>000560&nbsp; &nbsp; &nbsp; &nbsp;READ IN-FILE AT END<br>000570&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;MOVE 'Y' TO EOF-FLAG<br>000580&nbsp; &nbsp; &nbsp; &nbsp;NOT AT END<br>000590&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;IF&nbsp; &nbsp; &nbsp;(CHAR-1 = '*')<br>000600&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; OR (CHAR-1 = '/')<br>000610&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; OR (CHAR-1 = '-') THEN<br>000620&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MOVE LINE-CODE-IN TO L-COMMENT<br>000630&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MOVE LINE-NUMBER TO L-NUM-COM<br>000640&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; WRITE LINE-CODE-OUT FROM NUMBER-COMMENT<br>000660&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ELSE<br>000670&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MOVE LINE-CODE-IN TO L-CODE<br>000680&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MOVE LINE-NUMBER TO L-NUM-CODE<br>000690&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; WRITE LINE-CODE-OUT FROM NUMBER-CODE<br>000720&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;END-IF<br>000730&nbsp; &nbsp; &nbsp; &nbsp;END-READ<br>000740&nbsp; &nbsp; &nbsp; &nbsp;INITIALIZE NUMBER-CODE NUMBER-COMMENT<br>000750&nbsp; &nbsp; &nbsp;END-PERFORM</tt></p></div> </blockquote><p>With Parrot and a COBOL compiler, you could allow a more modern langauge (say, Rakudo) to be embedded:</p><blockquote><div><p> <tt>000510 MAIN-PARA.<br>000520&nbsp; &nbsp; &nbsp;OPEN INPUT IN-FILE<br>000530&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; OUTPUT OUT-FILE<br>000535<br>000540+Rakudo<br>&nbsp; &nbsp; &nbsp; &nbsp;my $line_num = 0;<br>&nbsp; &nbsp; &nbsp; &nbsp;while &lt;C:IN-FILE&gt; {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;$line_num += 10;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;my $c_area =<nobr> <wbr></nobr>/^[-*/]/ ?? '' !! ' '; # is this a comment?<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;print C:OUT_FILE sprintf "%06d$c_area%-100s" =&gt; $lin_num, $line;<br>&nbsp; &nbsp; &nbsp; &nbsp;}<br>000550</tt></p></div> </blockquote><p>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.</p><p>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<nobr> <wbr></nobr>:)</p><p> <small>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 <em>might</em> be misled into thinking that the COBOL code can't possibly be correct (look at the variable names), but it is.</small> </p> Ovid 2009-11-24T11:27:37+00:00 journal How Not To Advertise Your Job Service <p>From the front page of <a href=""></a>:</p><blockquote><div><p>"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</p></div></blockquote><p>Yeah, that would make me rush right out and sign up! (Does just getting <em>close</em> to COBOL make you stupid?)</p> Ovid 2009-11-23T13:56:13+00:00 journal Hash Objects and AutoInflation <p> <small>Until the issues are sorted out with <a href=""></a>, I'll still be posting here for a while (probably cross-posting for a while after, too).</small> </p><p>Recently I've wanted a simple hash object:</p><blockquote><div><p> <tt>my $object = Hash::Object-&gt;new({<br>&nbsp; id&nbsp; &nbsp;=&gt; $some_id,<br>&nbsp; this =&gt; 'that',<br>&nbsp; name =&gt; 'john',<br>});<br> <br>print $object-&gt;name; # john</tt></p></div> </blockquote><p>The problem is that current implementations I've found have limitations. One uses <tt>AUTOLOAD</tt> so <em>any</em> 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.</p><blockquote><div><p> <tt>my $object = Hash::Object-&gt;new(<br>&nbsp; data =&gt; {<br>&nbsp; &nbsp; id&nbsp; &nbsp;=&gt; $some_id,<br>&nbsp; &nbsp; this =&gt; 'that',<br>&nbsp; &nbsp; name =&gt; 'john',<br>&nbsp; },<br>&nbsp; inflate =&gt; sub { Customer-&gt;find({ id =&gt; shift-&gt;id }) }<br>);<br> <br>print $object-&gt;name;<br> <br># inflates to full Customer object and redispatches method<br>print $object-&gt;fullname;</tt></p></div> </blockquote><p>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 <em>probably</em> want, but will transparently work like the real thing if needed.</p><p>This is on the CPAN, yes? What's it called?</p> Ovid 2009-11-23T11:40:19+00:00 journal <p>It's official! We've a new blogging site available for the Perl community. <a href="">Dave Cross has now made the announcement</a>. I've a <a href="">blog post over there explaining a few things about it</a>. It's still alpha and there will be bugs, so keep that in mind. That being said, play around and have fun.</p> Ovid 2009-11-20T09:03:36+00:00 journal Why no plan for nested TAP? <p>At least one person has objected quite strongly to <a href="">my patch for Test::Builder which adds an implicit <tt>done_testing()</tt> to subtests with no plan</a>. I was kind of surprised with the vehemence of the discussion, so I want to clear this up.Consider the following test subtests:</p><blockquote><div><p> <tt>subtest 'with plan' =&gt; sub {<br>&nbsp; &nbsp; plan =&gt; 2;<br>&nbsp; &nbsp; is $this, $that, 'this is that';<br>&nbsp; &nbsp; is $foo,&nbsp; $bar,&nbsp; 'foo is bar';<br>};<br> <br>subtest 'without plan' =&gt; sub {<br>&nbsp; &nbsp; is $this, $that, 'this is that';<br>&nbsp; &nbsp; is $foo,&nbsp; $bar,&nbsp; 'foo is bar';<br>};</tt></p></div> </blockquote><p>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.</p><p>Unlike with the overall test program, you know <em>exactly</em> 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:</p><blockquote><div><p> <tt>use Test::Most;&nbsp; END { done_testing() }</tt></p></div> </blockquote><p>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.</p> Ovid 2009-11-17T11:24:13+00:00 journal The Obligatory Go Language Post <p>So I've been checking out Google's new "Go" language. There's an interesting example at <a href="">the Go tutorial</a>. Specifically, the following code is a simple very of "echo".</p><blockquote><div><p> <tt>package main<br> <br>import (<br>&nbsp; &nbsp; "os";<br>&nbsp; &nbsp; "flag";<nobr> <wbr></nobr>// command line option parser<br>)<br> <br>var omitNewLine = flag.Bool("n", false, "don't print final newline");<br> <br>const (<br>&nbsp; &nbsp; Space&nbsp; &nbsp;= " ";<br>&nbsp; &nbsp; Newline = "\n";<br>)<br> <br>func main() {<br>&nbsp; &nbsp; flag.Parse();<br>&nbsp; &nbsp; s<nobr> <wbr></nobr>:= "";<br>&nbsp; &nbsp; for i<nobr> <wbr></nobr>:= 0; i &lt; flag.NArg(); i++ {<br>&nbsp; &nbsp; &nbsp; &nbsp; if i &gt; 0 {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; s += Space;<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; s += flag.Arg(i);<br>&nbsp; &nbsp; }<br>&nbsp; &nbsp; if !*omitNewLine {<br>&nbsp; &nbsp; &nbsp; &nbsp; s += Newline<br>&nbsp; &nbsp; }<br>&nbsp; &nbsp; os.Stdout.WriteString(s);<br>}</tt></p></div> </blockquote><p>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.</p><p>You might have noticed the <tt>var s string = "";</tt> 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:</p><blockquote><div><p> <tt>var s string = "";<br>var s = "";&nbsp; &nbsp;// go knows you wanted a string<br>s<nobr> <wbr></nobr>:= "";&nbsp; &nbsp; &nbsp;<nobr> <wbr></nobr>// same thing</tt></p></div> </blockquote><p>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 <em>think</em> you're assigning to a variable but you've mistyped the name and you're also declaring it.</p><p>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 <a href="">his initial surprise at being introduced to objects</a>. His background is mathematical in nature and he just didn't understand the need for type hierarchies.</p><p>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.</p><p>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).</p> Ovid 2009-11-15T19:25:24+00:00 journal Vim: Automatically opening POD as a PDF <p>Doing a bit of POD munging and using <a href="">Pod::Parser::Groffmom</a> 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:</p><blockquote><div><p> <tt>au! FileType pod&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;:call PodMappings()<br> <br>function! PodMappings()<br>&nbsp; &nbsp; noremap &lt;buffer&gt;<nobr> <wbr></nobr>,r<nobr> <wbr></nobr>:call PodToPDF()&lt;cr&gt;<br>endfunction<br> <br>function! PodToPDF()<br>&nbsp; &nbsp; let filename&nbsp; &nbsp;= bufname("%")<br>&nbsp; &nbsp; let postscript = filename . ".ps"<br>&nbsp; &nbsp; let command&nbsp; = 'perl $(which pod2mom) --cover --toc --ps '<br>&nbsp; &nbsp; &nbsp; &nbsp; \ . filename<br>&nbsp; &nbsp; &nbsp; &nbsp; \ . ' &amp;&amp; open ' . postscript<br>&nbsp; &nbsp; echo system(command)<br>endfunction</tt></p></div> </blockquote> Ovid 2009-11-15T13:03:47+00:00 journal Vim: Does Your Pod Have Valid Perl? <p>After writing some <a href="">vim code to run your POD code</a>, I realized I needed another snippet to simply tell me if my POD code compiled (without running it). The vim mapping:</p><blockquote><div><p> <tt>vnoremap &lt;silent&gt; &lt;leader&gt;c<nobr> <wbr></nobr>:!perl ~/bin/validperl&lt;cr&gt;</tt></p></div> </blockquote><p>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 <tt>validperl</tt>:</p><blockquote><div><p> <tt>#!/usr/bin/env perl<br> <br>use strict;<br>use warnings;<br>use File::Temp 'tempfile';<br> <br>my $tmpdir = '/var/tmp';<br> <br>my ( $fh, $snippet ) = tempfile(<br>&nbsp; &nbsp; 'eval_XXXX',<br>&nbsp; &nbsp; SUFFIX =&gt; '.pl',<br>&nbsp; &nbsp; DIR&nbsp; &nbsp; =&gt; $tmpdir,<br>);<br>my $code = do { local $/; &lt;STDIN&gt; };<br>print $fh $code or die "Could not print code to ($snippet): $!";<br>close $fh or die "Could not close ($snippet): $!";<br> <br>my $perl = $^X;<br>print $code;<br>my $output = qx{ $perl -Ilib -c $snippet 2&gt;&amp;1 };<br>exit if $output =~ m{^$tmpdir/eval_\ syntax OK$};<br>$output =~ s/\n/\n<nobr> <wbr></nobr>/g;<br>print " __END__\n $output";</tt></p></div> </blockquote> Ovid 2009-11-14T10:25:27+00:00 journal Implicit "done_testing()" in subtests <p>Per <a href="">a previous blog entry</a>, I've submitted a pull request on github to implement an implicit <tt>done_testing()</tt> on subtests with no plan. This is due to the following:</p><blockquote><div><p> <tt>subtest 'trim' =&gt; sub {<br>&nbsp; &nbsp; plan tests =&gt; 2;<br>&nbsp; &nbsp; # snip<br>};<br> <br>subtest 'escape' =&gt; sub {<br>&nbsp; &nbsp; plan tests =&gt; 2;<br>&nbsp; &nbsp; # snip<br>};<br> <br>subtest 'interior sequences' =&gt; sub {<br>&nbsp; &nbsp; plan tests =&gt; 6;<br>&nbsp; &nbsp; # snip<br>};</tt></p></div> </blockquote><p>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:</p><blockquote><div><p> <tt>subtest 'some subtest' =&gt; sub {<br>&nbsp; &nbsp; isa_ok my $cust = Customer-&gt;new({<br>&nbsp; &nbsp; &nbsp; given&nbsp; =&gt; 'John',<br>&nbsp; &nbsp; &nbsp; family =&gt; 'Public' }<br>&nbsp; &nbsp; ), 'Customer';<br>&nbsp; &nbsp; can_ok $cust, 'given';<br>&nbsp; &nbsp; is $cust-&gt;given, 'John',<br> <br>&nbsp; &nbsp; can_ok $cust, 'family';<br>&nbsp; &nbsp; is $cust-&gt;family, 'Public';<br>};</tt></p></div> </blockquote><p> <tt>done_testing()</tt> 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.</p> Ovid 2009-11-13T17:21:03+00:00 journal