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 ]

ferreira (5993)

ferreira
  (email not shown publicly)
http://www.ferreira.triang.net/

Just another Brazilian Perl hacker.

Journal of ferreira (5993)

Saturday February 09, 2008
12:14 PM

Another context feature

My original title was "Another context trap", but I changed my mind. Read on.

Easy things are supposed to be easy to write in Perl, right? Let's try this one: write an (efficient) identity subroutine one that returns the arguments given to it.

Ok. Now you write down your solution and come back to read the rest of it.

That was my first attempt:

my $id = sub { return @_; }

And it looked like a good idea at first, as the @_ gets all the sub arguments (whether they be zero, one or many). And it seemingly worked.

$id->()        returns ()
$id->(42)      returns (42)
$id->(42,42)   returns (42,42)

Except that I was not totally honest, and these succeed only when the function is called at list context. If that's not the case, we have:

$c = $id->(42);   # 1 gets assigned to $c (from scalar @_)
($a) = $id->(42); # good, 42 gets assigned to $c

The quick solution is to take into account the calling context and write down the code as:

$id = sub {
    wantarray : @_ ? $_[0]
}

The fault of this is a Perl feature that most other programming languages don't have: sensitivity to calling context. Those others are happily relieved of this because they are poorer in semantics than Perl in that aspect.

The identity function needs to be defined from a domain into the same domain: A -> A. Then, if we consider the non-void contexts Perl 5 provides: list and scalar, we have not one but two identity functions to consider. Namely,

sub { @_ }    # for list context, LIST -> LIST
sub ($) { $_[0] } # for scalar context, SCALAR -> SCALAR

Note. The sneaky prototype in the last sub definition entered the scene to guarantee the homomorphism between the domain and image, that was not tested in the previous definition. So to be 100% correct, that should do it:

sub {
    if ( wantarray ) {
        @_;
    } else {
        die "too many arguments" unless @_==1;
        $_[0];
    }
}

The trap in this case is more like a fault of all other programming languages that don't have call context sensitivity. Because if they did, like Perl, they would push you up to think harder about some concepts like identity itself.

What Perl 6 will have to do with this? You bet no one is going to draw back and "relieve" Perl 6 of that extra expressiveness her mother language has. On contrary, Perl 6 will have even more call context sensitivity. But IIRC you will be able to define nice multisubs which dispatch on return type and will avoid unintented uses.

Hm, how they would look like? I am not sure. Maybe

multi sub id(Any $x -> Any: ) { $x }

Thursday February 07, 2008
01:08 PM

A Subtlety of 'reverse'

A few days ago I was bitten by the dual nature of reverse.

$s = reverse 'xyz'; # 'zyx'
@a = reverse qw(a b c); # qw(c b a)

This is even worse because reverse in scalar context may receive a LIST as argument and concatenates the reverse string of each element.

$s = reverse qw(abc mni xyz); # 'zyxinmcba'

There was a code where a method history was meant to return an array and got used in a few places this way:

$history_size = $o->history();

which worked ok, until I found a subclass implementation which had been coded like this:

sub history {
    shift;
    return ( reverse @history );
}

and the assumption that it should return the (history) array size when called in scalar context failed miserably. The solution was to document what it was supposed to return in list and scalar contexts and to change the implementation to:

sub history {
    shift;
    return my @h = reverse @history;
}

That's the kind of thing I remember when someone says: "What's so wrong with Perl 5 that we might need Perl 6?"

That's the kind of subtlety that caught you by surprise occasionally, beginner or not. Idiosyncracies like that put a burden at the programmer which has not a perfect memory (and I am one of such programmers unfortunately, I have to admit) and makes some feel that a Perl guru is needed to detect, solve and explain such bits. This kind of weird behavior leads sometimes to workarounds because there is no time to think about what's wrong with that f... piece of code. And then it distorts into ugly things that contributes to the bad fame of our favourite language.

Such ugly things go like a current joke on Portuguese ortography. A friend tells the other: "Write me a check of 'sessenta' Brazilian Reais" -- "How dow I spell 'sessenta'?" -- "Well, make two checks of thirty." (Background: the word "sessenta" (sixty) may raise doubts to careless people about the right spelling: "sesenta", "seçenta", "sessenta".)

If Perl 6 fails to get rid of such subtleties (and this is one of its design principles), it will have failed to be the improvement of the Perl language it was supposed to be.

Friday January 25, 2008
01:41 PM

SMTP/SASL authentication for CPAN::Reporter

I wrote a monkeypatch (dirty, I have to confess) so that I could use CPAN::Reporter with my ISP mail server which requires authentication.

I had to do it by touching Test::Reporter as well. They will be available in CPAN at:

In Test::Reporter, a new accessor net_smtp_args was created which should be filled with a hash ref. If it contains something like:

{   auth => { user => 'me', pass => '***' } }

and Net::SMTP is the current transport, it will attempt to do SASL authentication after opening the connection.

In CPAN::Reporter, the changes allow the code to read from the config file ~/.cpanreporter/config.ini two config values which get passed into Test::Reporter:

# to do SMTP/SASL authentication, add these to ~/.cpanreporter/config.ini
smtp_auth_user=me
smtp_auth_pass=***

This is not a permanent solution because CPANT::Testers::Transport::* is in the works to replace Test::Reporter which will allow more natural/elegant approaches to that.

Monday January 14, 2008
05:51 PM

WWW::CPAN->query()

WWW::CPAN is a work in progress (slow progress, to be honest). At 0.004 release, its API got one more method, query(). The whole API is:

  • new - good old constructor
  • fetch_distmeta - grab META.yml (META.json) from CPAN distributions
  • query - do simple queries and get the result as Perl data

Ain't that promising? Everyone will use it when 0.999 release arrives. (Yes, updates are by +0.001 increments.)

Friday December 28, 2007
03:53 PM

Perl 6 micro-articles just now

This week has seen a turmoil of emotions surrounding Perl 6. (Just take a look at the last articles here at use.perl and perlbuzz.) This entry is just to gladly announce that in this very moment (Dec 28 2007 18:30 GMT-0200) three microarticles of the series on Perl 6 operators are in The Hot 25 list of O'Reilly Network Blogs.

It may be due to other causes:

  • I faithfully provided one article from Monday to Friday for the last two weeks;
  • This is end-of-year time and reading habits may be different;
  • I am not quite sure of the criteria that make blog entries appear there in The Hot 25 and maybe it's just noise that took these articles to those positions (#5, #13, #23).

But on the other hand, given that I am not that endowed for writing, I rather believe that

  • Perl 6 still captures curiosity and attention of people out there;
  • People do not want to lose the opportunity (to learn, use, criticize, think about, etc.) when Perl 6 is finally released.

So I want to thank everyone that contributed to the current state of Perl 6-related development and to wish much fun in the future work that will bring us this long-awaited Christmas gift.

12:01 PM

The need for SUPER

Also known as "The trap of SUPER::method"

I never have grokked SUPER and what exactly it could do for me. Until I wrote Class::Constructor::Factory.

Class::Constructor::Factory is a helper module to prevent me to spend time writing constructors after using a module like Class::Accessor (and siblings) that gave me for free handy accessors/mutators for object fields. Those modules also gave me a constructor for free. But I am never happy with constructors without a way to specify defaults when initial field values are not given.

So C::C::F is a step towards a more automated way to get better constructors for free and, in a near future, to write classes with less effort. Actually, using the 0.001 version of the module looks like this:

package Foo;

use Class::Constructor::Factory;
use base qw( Class::Accessor Class::Constructor::Factory );

__PACKAGE__->mk_constructor0({
  foo => 42,
  bar => 'fourty-two',
});
__PACKAGE__->mk_accessors(qw( foo bar ));

The thing is that C::C::F augments the actual constructor provided by the IS-A chain of the new package with handling of defaults. So a closure is built and then installed into &Foo::new to work out the wanted magic.

my $foo = Foo->new();
is( $foo->foo, 42 );
is( $foo->bar, 'fourty-two' );

That is rather straightforward and involved code which looked like this:

package Class::Constructor::Factory;

...

sub make_constructor0 {
  my $self = shift;
  ...

  # return a closure
  return sub {
    my $self = shift;
    ...
    return $self->SUPER::new->( $self, \%f ); # XXX the offender
  };
}

I must say that this code is deceptively simple and wrong. Because ->SUPER::new tried to invoke the &new of Class::Constructor::Factory superclasses (which does not exist). I understood why by reading the docs of SUPER and perlobj. The relevant quote is:

"It is important to note that SUPER refers to the superclass(es) of the current package and not to the superclass(es) of the object."

So even after the closure was installed into the Foo namespace, ->SUPER::new yet referred to the superclass of the package where the code was compiled, not doing what I wanted.

The solution is to use SUPER and then rewrite the offender code line as:

    return $self->super('new')->( $self, \%f );

After this, the &new is searched correctly among the superclasses of the object and everything is just fine.

This entry is just to remind me that ->SUPER::method and dynamic code generation (or equivalently dealing with closures in namespaces other than where they were compiled) is at least misleading. I don't claim to have understood all the issues SUPER may address, but I learned something. Thanks, chromatic! And maybe this trap may be turned off in the future by toogling a feature in a future Perl 5 version.

Saturday December 22, 2007
02:37 PM

More Perl 6 micro-articles

For the next week, I have some drafts of micro-articles on Perl operators:

I would really appreciate feedback on these texts. Corrections, suggestions, etc.

Monday December 17, 2007
02:38 PM

Five Perl 6 micro-articles

So far I published more two articles at OnLAMP:

and got to complete three drafts for the next ones:

I would appreciate that interested people read them and point mistakes and improvements to be done.

P.S. Yeah, sadly I know that some links at OnLAMP are wrong or missing. But I am afraid that MT changes URL again if I try to update the articles. I don't know what is worse.

Tuesday December 11, 2007
03:15 PM

Micro-articles again

After a long pause, I am back to the business of writing the micro-articles on Perl 6 operators.

The article I want to publish tomorrow is about boolean operators and it is here. I welcome corrections and suggestions.

Monday December 10, 2007
10:59 AM

BEGIN { use_ok } keeps biting

The fearless Michael Schwern kept his word and brought back the Test-Simple fix for BEGIN { use_ok } bug. (If you don't know what I am saying, read this).

Some CPAN dists remain unfixed and those who upgraded the basic test modules will see an error while testing. Outstanding examples are:

Notice that the fix called for in this distributions is a real test bug. A contrived example is of the form:

use Test::More;

if ( $exp_which_tells_test_should_be_skipped ) {
    plan tests => 1; # this will happen at runtime
} else {
    plan 'skip_all' => 1; # that too
}

BEGIN { use_ok 'File::Temp' } # at compile-time

ok(1);

When Test::Builder had the bug, it swallowed the exception during BEGIN { use_ok } which announced a test before planning. Also, the test count should not include the use_ok to get pass this point. Yes, for some time, we authors have introduced not one, but two bugs in this type of code to make it work. Now it is time to write it down correctly.

use Test::More;

BEGIN {
    if ( $exp_which_tells_test_should_be_skipped )     {
        plan tests => 2;
    } else {
        plan 'skip_all' => 1;
    }
}

BEGIN { use_ok 'File::Temp' } # at compile-time

ok(1);

Bonus point: The fixed version works ok with the old (buggy) and the new Test-Simple.