31 Jul 2010

feedPlanet Perl

Perl 6 screencast - part 5 - hashes

Direct link to the Perl 6 screencast about hashes

See more Perl 6 entries.

Perl 6 Code examples

Hashes in Perl 6 are denoted using % sign: Creating a hash

  my %h = "Foo" => 1, "Bar" => 2;
  

printing it out for debugging purposes:

  say %h.perl;    # {"Foo" => 1, "Bar" => 2}

printing the value of a single key:

  say %h{"Foo"};  # 1
  

The quotation marks are required around the string:

  say %h{Foo};    # Could not find sub &Foo

You can use variables without quoting them:

  my $name = "Foo";
  say %h{$name};   # 1

Recall from the previus section that you can use the angle brackets to quote a number of strings and create a list of them:

  say <Foo Bar>;   # FooBar
  

This notation can be used to eliminate the need for quotation marks:

  say %h<Foo>;     # 1

You can actually use multiple keys there fetching a list of values of a hash slice:

  say %h<Foo Bar>;  # 1 2

Using the "perl" method just further proves that you get back a list of values

  say %h<Foo Bar>.perl;  # (1, 2)

In order to fetch all the keys you can use the ".keys" method and then you can iterate over the individual keys and fetch the respective values:

  for %h.keys -> $k { say "$k %h{$k}"; }

There is also a ".values" method that will return the list of values. Even though in our case the values are unique in the general case you cannot easily get back the keys from the values:

  for %h.values -> $v { say $v; }

In case you prefere to iterate over the key-value pairs for that you can use the ".kv" method:

  for %h.kv -> $k, $v { say "$k - $v"; }

To add another key with its value you can use the following code:

  %h<Moo> = 3;

  say %h.perl;    # {"Moo" => 3, "Foo" => 1, "Bar" => 2}

If the key already exists this will replace the value in the hash:

  %h<Moo> = 4;
  say %h.perl;   # {"Moo" => 4, "Foo" => 1, "Bar" => 2}

On the other hand in Perl 6 you can also use the ".push" method on a hash that will add the value to the given key creating an array as the value of that key:

  %h.push( 'Moo' => 5 );
  say %h.perl;   # {"Moo" => [4, 5], "Foo" => 1, "Bar" => 2}


31 Jul 2010 2:49pm GMT

30 Jul 2010

feedPlanet Perl

Links for 2010-07-30

30 Jul 2010 10:05pm GMT

Strawberry Perl July 2010 is coming soon...

Right now, I've built the first release candidate. Links are as follows:

http://strawberryperl.com/download/5.10.1.3/strawberry-perl-5.10.1.3.msi
http://strawberryperl.com/download/5.10.1.3/strawberry-perl-5.10.1.3.zip
http://strawberryperl.com/download/5.10.1.3/strawberry-perl-5.10.1.3-ddrive.msi

http://strawberryperl.com/download/5.12.1.0/strawberry-perl-5.12.1.0.msi
http://strawberryperl.com/download/5.12.1.0/strawberry-perl-5.12.1.0.zip
http://strawberryperl.com/download/5.12.1.0/strawberry-perl-5.12.1.0-portable.zip

http://strawberryperl.com/download/5.12.1.0/strawberry-perl-5.12.1.0-64bit.msi
http://strawberryperl.com/download/5.12.1.0/strawberry-perl-5.12.1.0-64bit.zip

Tomorrow is the planned official release date, and I'll upload them to the other main download sites then, if there are no issues raised before then.




( If you're curious about how I BUILD Strawberry once I've gotten the modules written: )

30 Jul 2010 9:41pm GMT

I want Perl Testing Best Practices

[I actually wrote this a long time ago and it's been stuck in the draft status. I don't have answers for these yet.]

I've been swamped with work lately, and despite perl5-porters giving me and everyone else plenty of time to update all of our modules for the next major release, I basically ignored Perl 5.11. Life sucks sometimes, then they release anyway. This isn't really a big deal because all the CPAN Testers FAILs go to a folder that I look at all at once. It's a big deal for other people when they try to install a borken dependency and cpan(1) blows up.

However, my negligence in updating my CPAN modules reminded me of a possible best practice that has been on my mind for a long time, and which I've casually brought up at a couple Perl QA workshops since I've written several Test modules. Don't rush to say Test::Class just yet.

In a nutshell, Perl's testing framework is a stew of real tests and implied tests, and we can't tell the difference. Some of those tests use Test::Builder-based functions that generate test output:

 ok( $some_value, 'Some value is true' );
 like( $var. $regex. 'Hey, it matches!' );

Some things that we don't normally think of "tests" actually are:

 use Test::File;

By using my Test::File module, you are asserting that it passes all of its tests too. If you don't have it installed, cpan(1) will, by default, try to fetch that distribution and run its tests (cpanminus decidedly won't).

The problem with a Test module is that its tests working or failing have nothing to do with the code that you are trying to test, but a failure to load my module, which is probably completely my fault, but in the mess of output from a test failure, I usually don't get the blame.

So far, we don't have a strong practice for capturing problems in tests. In fact, despite the Perl community's otherwise good practices and coding standards, we don't pay attention to test script quality. In particular, we let our test scripts fail for all sorts of reasons that have nothing to do with the target code. Maybe I need to do something like this instead:

 eval {
      use Test::File;
      } or skip_all( ... );

Okay, that's one thing that bothers me about my tests. I also frequently micro-manage tests. Let's say that I want to test a method that needs to open a file. I'll have several checks in the setup because I want to ensure that I'm doing the right thing before I get to testing my method. That is, I want to test my test setup:

ok( -e $filename, "$filename is there" );
is( md5( $filename ), $expected_md5, "$filename looks like it has the right stuff" );
is( -s $filename, $expected_size, "$filename has the right size" );

Test::Class (and maybe some other frameworks) have setup and tear down methods that mitigate this, but that's not really my problem. If one of these setup methods fail, it's a failure of my test suite but not necessarily my module. I'd like to report that differently.

I've thought that TAP's binary ok / not ok was a bit limited. I'd actually like to have ok / not ok / unable to test / unknown. "Unable to test" is different than "skip". Consider architecture dependent tests that won't run-those are skip tests. If Test::Pod is not installed however, I'd like to see a report that explicitly says "unable to test". It's the undef of the testing world. I'm not actually proposing a change to TAP. Maybe there's some other practice can do the same thing. TAP isn't the point, really, I don't think. As a community, we just don't haven't paid that much attention to what each call to a Test::Builder-y function is really testing and in which column we should put the result. I've been thinking that maybe I should only call a Test::Builder-y thing when I want to report a result that directly relates to the code that I am testing.

Finally, I don't have a habit of documenting my tests. Sure, I put in code comments and the like, but I'm talking about full-on embedded pod that ties together some notional spec with what the particular test file is going to do with it. I feel guilty for about five seconds before I move on to something else.

A lot of people think about the underpinnings of our test system, but we've spent very little time at Perl QA workshop thinking about what a programmer should type out as they write a test file. To solve this, I think the first step is to probably just collect a bunch of stories from people about the practices they use and what nags at them at this level.

30 Jul 2010 7:02pm GMT

feedPlanet Perl Six

Audrey Tang: Rakudo Star:Perl 6 正式起飛(五之五)

(This is a translation of masak++'s excellent Perl 6 anniversary post, part 5 of 5.)


我們正在寫這段歷史。

七月二十九日,Rakudo 團隊正式釋出「樂土之星(Rakudo Star)」,也是 Rakudo Perl 計劃的第一個正式發行版本。(請按此處下載。)

在我看來,這個時機真是恰當極了。

在 Jon Orwant 擲杯之後的十年,Perl 6 團隊向全世界說:「這是我們的作品。幾年來我們孜孜不倦,對它切磋琢磨,如今它已曖曖含光、足堪重任。請試試看,用它來做些有趣的事吧!」

這些年來,從瓷杯創生的 Perl 6 專案,讓包括筆者在內的許多人興奮不已。

現在是讓更多人加入的時候了。

我們在此誠摰地邀請您,一同踏入這片樂土。

30 Jul 2010 4:59am GMT

29 Jul 2010

feedPlanet Perl Six

Jonathan Worthington (6guts): Rakudo Star, and where from here

After much hard work by a lot of people, Rakudo Star is here! I joined in with Rakudo development about two and a half years ago, and since then it's been quite a ride. The rough story of how I got into Rakudo is that I drunk some amount of beer at a party at OSCON, and ended up expressing an interest in implementing junctions for what was then only known as "the Perl 6 compiler for Parrot". Little did I know that implementing junctions fully would mean implementing multiple dispatch, which in turn depended on the type system, which in turn depended on OO. Spurred on by encouragement from the community, I decided that instead of running away screaming, I'd take a crack at them. I'm glad I stayed on. :-)

Rakudo Star is certainly a step on a journey rather than a destination, but I find a lot to be happy about in today's release. The feature set delivers on a lot of the things Perl 6 has promised: Perl 6 grammars and regexes, multiple dispatch, OO including roles and introspection, laziness, junctions, types, meta-operators, user-defined operators and, of course, Perl 6′s take on many of the basic things you'd just expect to find in a language. There is also a decent variety of modules which reflect the growing Perl 6 ecosystem, including serializers for JSON and YAML, database connectivity, HTTP client and server, mathematical modeling, mock object testing, SVG and more. There's a partial book to help people get started. And for Windows users, there's now also a binary installer - something that I hope will be helpful (since while Rakudo will build on Windows without too much hassle, most people don't have such a build environment to hand, and it's quite a barrier to have to set it up).

Equally, there's still plenty of work to do - the release announcement lays down a pretty good list of the major points. Many of the Rakudo developers will be meeting at YAPC::Europe next week, and I expect one thing that will come out of that will be an updated roadmap for Rakudo development, or at least the discussions that let us go away and write one. I expect a big focus from here on in is going to be speed. Another likely area of interest will be targeting additional backends. And, of course, we've got still got features left to implement - from here it's a matter of prioritizing.

Anyway, enjoy Rakudo *, and I look forward to enjoying a beer with those of you who'll be at YAPC next week. :-)


29 Jul 2010 11:12pm GMT

Jan Ingvoldstad: Rakudo Star is here

The wait is over, and a usable Rakudo-based Perl 6 distribution is ready for early adopters. Yay!

More and more of Perl 6 is implemented in Perl 6. That is a very good tendency.

29 Jul 2010 2:29pm GMT

feedPlanet Perl

Help?

(Before I begin, I should clarify I did not write this code, I'm just trying to maintain it)

The following error is the first thing spat out by make test for the Padre sync server, located at http://svn.perlide.org/padre/trunk/Madre-Sync.

Wasn't the move of Catalyst to Moose going to make things easier?

Can someone explain how you debug this?

I get the basics, I can see the "Can't locate Madre/Sync/Schema.pm". But that file should be, I think, automatically generated. And I don't really get how to dig down the 75 caller levels from the start to the end to work out where the actual functionality is failing...

not ok 1 - use Catalyst::Test;

# Failed test 'use Catalyst::Test;'
# at t\01app.t line 7.
# Tried to use 'Catalyst::Test'.
# Error: Couldn't load class (Madre::Sync) because: Couldn't instantiate component "Madre::Sync::Model::padreDB", "Can't locate Madre/Sync/Schema.pm i
n @INC (@INC contains: blib\lib blib\arch C:/strawberry/perl/lib C:/strawberry/perl/site/lib C:\strawberry\perl\vendor\lib .). at C:\strawberry\perl\vendor
\lib/Class/MOP.pm line 132
# Class::MOP::load_first_existing_class('Madre::Sync::Schema') called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 137
# Class::MOP::load_class('Madre::Sync::Schema') called at C:\strawberry\perl\vendor\lib/Catalyst/Model/DBIC/Schema/Types.pm line 21
# Catalyst::Model::DBIC::Schema::Types::__ANON__[C:\strawberry\perl\vendor\lib/Ca talyst/Model/DBIC/Schema/Types.pm:21]('Madre::Sync::Schema') called
at C:\strawberry\perl\vendor\lib/Moose/Meta/TypeCoercion.pm line 63
# Moose::Meta::TypeCoercion::__ANON__[C:\strawberry\perl\vendor\lib/Moose/Meta/Ty peCoercion.pm:67]('Madre::Sync::Schema') called at C:\strawberry\per
l\vendor\lib/Moose/Meta/TypeCoercion.pm line 97
# Moose::Meta::TypeCoercion::coerce('Moose::Meta::TypeCoercion=HASH(0x4a2b444)', 'Madre::Sync::Schema') called at C:\strawberry\perl\vendor\lib/Moose
/Meta/TypeConstraint.pm line 90
# Moose::Meta::TypeConstraint::coerce('Moose::Meta::TypeConstraint=HASH(0x4a29854 )', 'Madre::Sync::Schema') called at C:\strawberry\perl\vendor\lib/M
ooseX/Types/TypeDecorator.pm line 206
# eval {...} called at C:\strawberry\perl\vendor\lib/MooseX/Types/TypeDecorator.pm line 205
# MooseX::Types::TypeDecorator::AUTOLOAD('MooseX::Types::TypeDecorator=HASH(0x4a3 1424)', 'Madre::Sync::Schema') called at C:\strawberry\perl\vendor\l
ib/Moose/Meta/Attribute.pm line 743
# Moose::Meta::Attribute::_coerce_and_verify('Moose::Meta::Attribute=HASH(0x4b467 fc)', 'Madre::Sync::Schema', 'Madre::Sync::Model::padreDB=HASH(0x4db
7c64)') called at C:\strawberry\perl\vendor\lib/Moose/Meta/Attribute.pm line 398
# Moose::Meta::Attribute::initialize_instance_slot('Moose::Meta::Attribute=HASH(0 x4b467fc)', 'Moose::Meta::Instance=HASH(0x4db7ed4)', 'Madre::Sync::M
odel::padreDB=HASH(0x4db7c64)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Class/MOP/Class.pm line 567
# Class::MOP::Class::_construct_instance('Moose::Meta::Class=HASH(0x4942ffc)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Class/MOP/C
lass.pm line 540
# Class::MOP::Class::new_object('Moose::Meta::Class=HASH(0x4942ffc)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Moose/Meta/Class.pm
line 256
# Moose::Meta::Class::new_object('Moose::Meta::Class=HASH(0x4942ffc)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Moose/Object.pm lin
e 25
# Moose::Object::new('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4b404ec)') called at generated method (unknown origin) line 4
# Catalyst::Model::DBIC::Schema::new('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4b404ec)') called at C:\strawberry\perl\vendor\lib/MooseX/
Traits/Pluggable.pm line 131
# MooseX::Traits::Pluggable::new_with_traits('Madre::Sync::Model::padreDB', 'Madre::Sync') called at C:\strawberry\perl\vendor\lib/CatalystX/Componen
t/Traits.pm line 146
# CatalystX::Component::Traits::COMPONENT('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4c6b93c)') called at C:\strawberry\perl\vendor\lib/Cl
ass/MOP/Method/Wrapped.pm line 48
# Class::MOP::Method::Wrapped::__ANON__[C:\strawberry\perl\vendor\lib/Class/MOP/M ethod/Wrapped.pm:49]('Madre::Sync::Model::padreDB', 'Madre::Sync', '
HASH(0x4c6b93c)') called at C:\strawberry\perl\vendor\lib/Class/MOP/Method/Wrapped.pm line 89
# Catalyst::Model::DBIC::Schema::COMPONENT('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4c6b93c)') called at C:\strawberry\perl\vendor\lib/C
atalyst.pm line 2502
# eval {...} called at C:\strawberry\perl\vendor\lib/Catalyst.pm line 2502
# Catalyst::setup_component('Madre::Sync', 'Madre::Sync::Model::padreDB') called at C:\strawberry\perl\vendor\lib/Catalyst.pm line 2416
# Catalyst::setup_components('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Class/MOP/Method/Wrapped.pm line 54
# Class::MOP::Method::Wrapped::__ANON__[C:\strawberry\perl\vendor\lib/Class/MOP/M ethod/Wrapped.pm:64]('Madre::Sync') called at C:\strawberry\perl\ven
dor\lib/Class/MOP/Method/Wrapped.pm line 89
# Madre::Sync::setup_components('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Catalyst.pm line 1142
# Catalyst::setup('Madre::Sync') called at blib\lib/Madre/Sync.pm line 62
# require Madre/Sync.pm called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 114
# Class::MOP::__ANON__[C:\strawberry\perl\vendor\lib/Class/MOP.pm:118]() called at C:\strawberry\perl\vendor\lib/Try/Tiny.pm line 74
# eval {...} called at C:\strawberry\perl\vendor\lib/Try/Tiny.pm line 67
# Try::Tiny::try('CODE(0x36d759c)', 'Try::Tiny::Catch=REF(0x33a9584)') called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 125
# Class::MOP::load_first_existing_class('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 137
# Class::MOP::load_class('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Catalyst/Test.pm line 24
# Catalyst::Test::__ANON__[C:\strawberry\perl\vendor\lib/Catalyst/Test.pm:93]('Ca talyst::Test', 'all', 'HASH(0x36d768c)', 'HASH(0x25de3a4)') called a
t C:\strawberry\perl\vendor\lib/Sub/Exporter.pm line 493
# Sub::Exporter::_expand_group('Catalyst::Test', 'HASH(0x36d4ce4)', 'ARRAY(0x36d4994)', 'HASH(0x25de3a4)', 'HASH(0x36d755c)', 'HASH(0x25de334)') call
ed at C:\strawberry\perl\vendor\lib/Sub/Exporter.pm line 424
# Sub::Exporter::_expand_groups('Catalyst::Test', 'HASH(0x36d4ce4)', 'ARRAY(0x36d723c)', 'HASH(0x25de3a4)') called at C:\strawberry\perl\vendor\lib/S
ub/Exporter.pm line 742
# Sub::Exporter::__ANON__[C:\strawberry\perl\vendor\lib/Sub/Exporter.pm:756]('Cat alyst::Test', '-all', 'HASH(0x36cc8d4)') called at C:\strawberry\per
l\vendor\lib/Catalyst/Test.pm line 112
# Catalyst::Test::import('Catalyst::Test', 'Madre::Sync') called at (eval 11)[C:/strawberry/perl/lib/Test/More.pm:858] line 2
# main::BEGIN() called at blib\lib/Madre/Sync.pm line 0
# eval {...} called at blib\lib/Madre/Sync.pm line 0
# eval 'package main;
# use Catalyst::Test @{$args[0]};
# 1;
#
# ;' called at C:/strawberry/perl/lib/Test/More.pm line 858
# Test::More::_eval('package main;\x{a}use Catalyst::Test @{$args[0]};\x{a}1;\x{a}', 'ARRAY(0x2308474)') called at C:/strawberry/perl/lib/Test/More.p
m line 833
# Test::More::use_ok('Catalyst::Test', 'Madre::Sync') called at t\01app.t line 7
# at C:\strawberry\perl\vendor\lib/MooseX/Types/TypeDecorator.pm line 208
# MooseX::Types::TypeDecorator::AUTOLOAD('MooseX::Types::TypeDecorator=HASH(0x4a3 1424)', 'Madre::Sync::Schema') called at C:\strawberry\perl\vendor\l
ib/Moose/Meta/Attribute.pm line 743
# Moose::Meta::Attribute::_coerce_and_verify('Moose::Meta::Attribute=HASH(0x4b467 fc)', 'Madre::Sync::Schema', 'Madre::Sync::Model::padreDB=HASH(0x4db
7c64)') called at C:\strawberry\perl\vendor\lib/Moose/Meta/Attribute.pm line 398
# Moose::Meta::Attribute::initialize_instance_slot('Moose::Meta::Attribute=HASH(0 x4b467fc)', 'Moose::Meta::Instance=HASH(0x4db7ed4)', 'Madre::Sync::M
odel::padreDB=HASH(0x4db7c64)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Class/MOP/Class.pm line 567
# Class::MOP::Class::_construct_instance('Moose::Meta::Class=HASH(0x4942ffc)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Class/MOP/C
lass.pm line 540
# Class::MOP::Class::new_object('Moose::Meta::Class=HASH(0x4942ffc)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Moose/Meta/Class.pm
line 256
# Moose::Meta::Class::new_object('Moose::Meta::Class=HASH(0x4942ffc)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Moose/Object.pm lin
e 25
# Moose::Object::new('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4b404ec)') called at generated method (unknown origin) line 4
# Catalyst::Model::DBIC::Schema::new('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4b404ec)') called at C:\strawberry\perl\vendor\lib/MooseX/
Traits/Pluggable.pm line 131
# MooseX::Traits::Pluggable::new_with_traits('Madre::Sync::Model::padreDB', 'Madre::Sync') called at C:\strawberry\perl\vendor\lib/CatalystX/Componen
t/Traits.pm line 146
# CatalystX::Component::Traits::COMPONENT('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4c6b93c)') called at C:\strawberry\perl\vendor\lib/Cl
ass/MOP/Method/Wrapped.pm line 48
# Class::MOP::Method::Wrapped::__ANON__[C:\strawberry\perl\vendor\lib/Class/MOP/M ethod/Wrapped.pm:49]('Madre::Sync::Model::padreDB', 'Madre::Sync', '
HASH(0x4c6b93c)') called at C:\strawberry\perl\vendor\lib/Class/MOP/Method/Wrapped.pm line 89
# Catalyst::Model::DBIC::Schema::COMPONENT('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4c6b93c)') called at C:\strawberry\perl\vendor\lib/C
atalyst.pm line 2502
# eval {...} called at C:\strawberry\perl\vendor\lib/Catalyst.pm line 2502
# Catalyst::setup_component('Madre::Sync', 'Madre::Sync::Model::padreDB') called at C:\strawberry\perl\vendor\lib/Catalyst.pm line 2416
# Catalyst::setup_components('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Class/MOP/Method/Wrapped.pm line 54
# Class::MOP::Method::Wrapped::__ANON__[C:\strawberry\perl\vendor\lib/Class/MOP/M ethod/Wrapped.pm:64]('Madre::Sync') called at C:\strawberry\perl\ven
dor\lib/Class/MOP/Method/Wrapped.pm line 89
# Madre::Sync::setup_components('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Catalyst.pm line 1142
# Catalyst::setup('Madre::Sync') called at blib\lib/Madre/Sync.pm line 62
# require Madre/Sync.pm called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 114
# Class::MOP::__ANON__[C:\strawberry\perl\vendor\lib/Class/MOP.pm:118]() called at C:\strawberry\perl\vendor\lib/Try/Tiny.pm line 74
# eval {...} called at C:\strawberry\perl\vendor\lib/Try/Tiny.pm line 67
# Try::Tiny::try('CODE(0x36d759c)', 'Try::Tiny::Catch=REF(0x33a9584)') called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 125
# Class::MOP::load_first_existing_class('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 137
# Class::MOP::load_class('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Catalyst/Test.pm line 24
# Catalyst::Test::__ANON__[C:\strawberry\perl\vendor\lib/Catalyst/Test.pm:93]('Ca talyst::Test', 'all', 'HASH(0x36d768c)', 'HASH(0x25de3a4)') called a
t C:\strawberry\perl\vendor\lib/Sub/Exporter.pm line 493
# Sub::Exporter::_expand_group('Catalyst::Test', 'HASH(0x36d4ce4)', 'ARRAY(0x36d4994)', 'HASH(0x25de3a4)', 'HASH(0x36d755c)', 'HASH(0x25de334)') call
ed at C:\strawberry\perl\vendor\lib/Sub/Exporter.pm line 424
# Sub::Exporter::_expand_groups('Catalyst::Test', 'HASH(0x36d4ce4)', 'ARRAY(0x36d723c)', 'HASH(0x25de3a4)') called at C:\strawberry\perl\vendor\lib/S
ub/Exporter.pm line 742
# Sub::Exporter::__ANON__[C:\strawberry\perl\vendor\lib/Sub/Exporter.pm:756]('Cat alyst::Test', '-all', 'HASH(0x36cc8d4)') called at C:\strawberry\per
l\vendor\lib/Catalyst/Test.pm line 112
# Catalyst::Test::import('Catalyst::Test', 'Madre::Sync') called at (eval 11)[C:/strawberry/perl/lib/Test/More.pm:858] line 2
# main::BEGIN() called at blib\lib/Madre/Sync.pm line 0
# eval {...} called at blib\lib/Madre/Sync.pm line 0
# eval 'package main;
# use Catalyst::Test @{$args[0]};
# 1;
#
# ;' called at C:/strawberry/perl/lib/Test/More.pm line 858
# Test::More::_eval('package main;\x{a}use Catalyst::Test @{$args[0]};\x{a}1;\x{a}', 'ARRAY(0x2308474)') called at C:/strawberry/perl/lib/Test/More.p
m line 833
# Test::More::use_ok('Catalyst::Test', 'Madre::Sync') called at t\01app.t line 7"Compilation failed in require at C:\strawberry\perl\vendor\lib/Class
/MOP.pm line 114.
# at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 121
# Class::MOP::__ANON__[C:\strawberry\perl\vendor\lib/Class/MOP.pm:125]('Couldn\'t instantiate component "Madre::Sync::Model::padreDB"...') called at
C:\strawberry\perl\vendor\lib/Try/Tiny.pm line 98
# Try::Tiny::try('CODE(0x36d759c)', 'Try::Tiny::Catch=REF(0x33a9584)') called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 125
# Class::MOP::load_first_existing_class('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 137
# Class::MOP::load_class('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Catalyst/Test.pm line 24
# Catalyst::Test::__ANON__[C:\strawberry\perl\vendor\lib/Catalyst/Test.pm:93]('Ca talyst::Test', 'all', 'HASH(0x36d768c)', 'HASH(0x25de3a4)') called a
t C:\strawberry\perl\vendor\lib/Sub/Exporter.pm line 493
# Sub::Exporter::_expand_group('Catalyst::Test', 'HASH(0x36d4ce4)', 'ARRAY(0x36d4994)', 'HASH(0x25de3a4)', 'HASH(0x36d755c)', 'HASH(0x25de334)') call
ed at C:\strawberry\perl\vendor\lib/Sub/Exporter.pm line 424
# Sub::Exporter::_expand_groups('Catalyst::Test', 'HASH(0x36d4ce4)', 'ARRAY(0x36d723c)', 'HASH(0x25de3a4)') called at C:\strawberry\perl\vendor\lib/S
ub/Exporter.pm line 742
# Sub::Exporter::__ANON__[C:\strawberry\perl\vendor\lib/Sub/Exporter.pm:756]('Cat alyst::Test', '-all', 'HASH(0x36cc8d4)') called at C:\strawberry\per
l\vendor\lib/Catalyst/Test.pm line 112
# Catalyst::Test::import('Catalyst::Test', 'Madre::Sync') called at (eval 11)[C:/strawberry/perl/lib/Test/More.pm:858] line 2
# main::BEGIN() called at C:\strawberry\perl\vendor\lib/Catalyst/Test.pm line 2
# eval {...} called at C:\strawberry\perl\vendor\lib/Catalyst/Test.pm line 2
# eval 'package main;
# use Catalyst::Test @{$args[0]};
# 1;
#
# ;' called at C:/strawberry/perl/lib/Test/More.pm line 858
# Test::More::_eval('package main;\x{a}use Catalyst::Test @{$args[0]};\x{a}1;\x{a}', 'ARRAY(0x2308474)') called at C:/strawberry/perl/lib/Test/More.p
m line 833
# Test::More::use_ok('Catalyst::Test', 'Madre::Sync') called at t\01app.t line 7
# BEGIN failed--compilation aborted at (eval 11)[C:/strawberry/perl/lib/Test/More.pm:858] line 2.

29 Jul 2010 1:23pm GMT

feedPlanet Perl Six

Patrick Michaud: Rakudo Star - an "early adopter" distribution of Perl 6

On behalf of the Rakudo and Perl 6 development teams, I'm happy to announce the July 2010 release of "Rakudo Star", a useful and usable distribution of Perl 6. The tarball for the July 2010 release is available from http://github.com/rakudo/star/downloads.

Rakudo Star is aimed at "early adopters" of Perl 6. We know that it still has some bugs, it is far slower than it ought to be, and there are some advanced pieces of the Perl 6 language specification that aren't implemented yet. But Rakudo Perl 6 in its current form is also proving to be viable (and fun) for developing applications and exploring a great new language. These "Star" releases are intended to make Perl 6 more widely available to programmers, grow the Perl 6 codebase, and gain additional end-user feedback about the Perl 6 language and Rakudo's implementation of it.

In the Perl 6 world, we make a distinction between the language ("Perl 6") and specific implementations of the language such as "Rakudo Perl". "Rakudo Star" is a distribution that includes release #31 of the Rakudo Perl 6 compiler [1], version 2.6.0 of the Parrot Virtual Machine [2], and various modules, documentation, and other resources collected from the Perl 6 community. We plan to make Rakudo Star releases on a monthly schedule, with occasional special releases in response to important bugfixes or changes.

Some of the many cool Perl 6 features that are available in this release of Rakudo Star:

There are some key features of Perl 6 that Rakudo Star does not yet handle appropriately, although they will appear in upcoming releases. Thus, we do not consider Rakudo Star to be a "Perl 6.0.0" or "1.0" release. Some of the not-quite-there features include:

In many places we've tried to make Rakudo smart enough to inform the programmer that a given feature isn't implemented, but there are many that we've missed. Bug reports about missing and broken features are welcomed.

See http://perl6.org/ for links to much more information about Perl 6, including documentation, example code, tutorials, reference materials, specification documents, and other supporting resources.

Rakudo Star also bundles a number of modules; a partial list of the modules provided by this release include:

These are not considered "core Perl 6 modules", and as module development for Perl 6 continues to mature, future releases of Rakudo Star will likely come bundled with a different set of modules. Deprecation policies for bundled modules will be created over time, and other Perl 6 distributions may choose different sets of modules or policies. More information about Perl 6 modules can be found at http://modules.perl6.org.

Rakudo Star also contains a draft of a Perl 6 book -- see "docs/UsingPerl6-draft.pdf" in the release tarball.

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

Rakudo Star releases are created on a monthly cycle or as needed in response to important bug fixes or improvements. The next planned release of Rakudo Star will be on August 24, 2010.

[1] http://github.com/rakudo/rakudo
[2] http://parrot.org/

29 Jul 2010 12:28pm GMT

feedPlanet Perl

Test::Class: why have tests in startup?

If you use Test::Class frequently, sooner or later you'll see the following:

sub startup : Tests(startup => 1) {
    my $test = shift;
    my $engines = $test->start_engines;
    ok $engines->are_running, 'Engines should start OK.';
}

At first blush that looks sensible, but I don't think it is. I'll explain my view of the problem and hope that others can explain why I might be wrong.

There are, in my opinion, two reasons not to use that construct. First, why is that a test? If that test fails, the rest of the tests in that class won't be run, but in this case, why not just die? Test control methods like startup, shutdown, setup and teardown shouldn't be an extra place to stuff tests, they're places to control the actual tests. If something has gone horribly wrong in them, just die and the rest of the tests in that class will be skipped.

Now that doesn't sound to everyone like a compelling argument, but what happens when you subclass?

sub startup : Tests(startup => 1) {
    my $test = shift;
    $test->next::method;
    ok $test->create_grue, 'Grue created';
}

Oops. Now you have a problem. That "next::method" has run a test in your superclass and you've run two tests instead of one (a patch to Test::Class could fix this, but you would likely break existing tests which workaround this issue). This means that you now have to count the tests in your superclass(es) startup method(s):

sub startup : Tests(startup => 2) {
    my $test = shift;
    $test->next::method;
    ok $test->create_grue, 'Grue created';
}

That looks wrong because you only see one test. Then when someone adds a test in a superclass startup, they've broken subclasses. Since there's no real reason (that I can see) to have tests in these test control methods and since they can be very fragile in the face of inheritance, why have them? I recommend that people don't use them and I've eliminated them in our production code at the BBC with no drawback. If something fails, just die and let Test::Class do the right thing.

Update: I completely forgot that you can use the following syntax to avoid counting superclass tests:

sub startup : Tests(startup => +1) {
    my $test = shift;
    $test->next::method;
    ok $test->create_grue, 'Grue created';
}

Note that you're specifying the additional number of tests, not the absolute number of tests. This renders much of my argument moot.

29 Jul 2010 7:16am GMT

our new media box

Last week, I was at OSCON. I have to write a lot more about that whole experience. For now, it's only relevant because it mean that when my Popbox arrived, I wasn't home. I checked some of the reviews and they were bad. Like, shockingly bad.

When I arrived home, Popbox had issued a few firmware updates, so I remained hopeful. Unfortunately, they utterly bricked the box. I sent it back and ordered an Acer Aspire Revo to use as an Ubuntu machine with XBMC. It showed up today.

It was pretty frustrating as attempt after attempt failed to get the darned thing working. I just finished watching an episode of Batman: The Animated Series, though, so I'm hoping that everything is now right with the world.

First, I couldn't get the XBMCLive system installed. I could get it onto a USB stick, but that would boot to a login prompt, not the XBMC system with an installer. I tried this a few times, and gave up in disgust. Then I tried to install it to a hard drive, but grub died. The drive changed its device name between setup and attempted install, but grub was dying too early for me to fix the setup.

Finally I installed Ubuntu 10.04 to a micro SD card and installed Ubuntu from there. After that, I let it do all of its upgrades, installed xbmc-standalone, and set it up to run that automatically on boot. This was progress!

Next up, it couldn't find my RaLink RT3090 wireless chip. The guys in #xbmc-linux were alternately helpful and not, but they kept my brain active while I kept looking. Finally, I found this bizarre solution in a forum:

As root:

mkdir -p /etc/Wireless/RT2860STA/
touch /etc/Wireless/RT2860STA/RT2860STA.dat
service network-manager restart

...and that's it. Wuh? Well, it worked.

So, I took the thing downstairs and hooked it up. Everything seemed okay, until I tried to play my first video. It took ages to buffer anything and playback was unacceptable. I'd gotten some grief from IRC about using wireless for streaming video, but I do this all the time already to my Xbox 360 and PS3. Further, I wasn't getting any audio over HDMI. I struggled with that for a while before finding another useful forum post suggesting that the HDMI output was muted, and that the only way to find it was to run the terminal alsamixer program and hit the undocumented "m for mute" command. That did the trick!

After that, I tried to play an episode of Batman, and it worked. Why was the wireless weird before? No idea. It would be nice to get a cable run, somehow, but I am in no hurry.

I also installed XBMC Remote on my iPhone, but I think it's sort of underwhelming. I'm not sure what I'll do in its stead, but I don't think it's a long term solution. I might just get an IR receiver and set up the XBMC in our Harmony remote.

My hope is that we can use this device to let Martha see whatever of her DVDs she wants without having to fumble with discs. Any other application is pure gravy.

29 Jul 2010 4:21am GMT

java2perl6api – Java to Perl 6 API translation – What, Why, and Whereto

In this post I'm going to talk about the java2perl6api project. What its goals are, why I think it's important, how it relates to a Perl 6 DBI, what exists now, what's needs doing, and how you can help.

Firstly I'd like to point out that, funnily enough, I'm not very familiar with Java or Perl6. It's entirely possible that I'll make all sorts of errors in the following details. If you spot any do please let me know.

Background

The Java language ecosystem is big and mature after years of heavy investment of time and money.

It doesn't have a central repository of Open Source modules like CPAN (though Maven repositories like these are similar I guess). It does, however, have a number of mature high quality class libraries, and a very large number of developers familiar with those libraries (more on that below).

Goals

The primary goal of the java2perl6api project is to make it easy to create Perl 6 class libraries that mirror Java equivalents. By mirror I mean share the same method names and semantics at a high level (though not at a low-level, more on that below).

Secondary goals are to do that well enough that:

Why?

Firstly, creating good APIs is hard. Java APIs like JDBC 3.0 and NIO.2 are the result of years of professional effort and demanding commercial experience. Why not build on that experience?

I appreciate that Java APIs are often limited by the constraints of the language, such as the lack of closures, and that Perl 6 can probably express any given set of semantics more effectively than Java. My point here is that some Java APIs embody, however inelegantly, years of hard won experience that we can benefit from. I'd rather make new mistakes than repeat old ones.

Secondly, there are many more Java developers than Perl developers. Many many more if job vacancies are any indication:

job vacancy trends for perl developer and java developer

I think we'd be foolish not to try to smooth the path for any Java developers who might be interested in Perl 6. The java2perl6api project is just one small aspect of that.

I really hope someone starts writing a "Perl 6 for Java Developers" tutorial. Perl 6 has the potential to become a very popular language1. Getting just a tiny percentage of Java developers (and Computer Science majors and their teachers) interested in it could be a big help.

Thirdly, any future DBI for Perl 6 and Parrot needs a much better foundation than the very limited and poorly defined one that underlies the Perl 5 DBI. I plan to adopt the JDBC 3.0 API and test suite for that internal role. (You could call this a "Test Suite Driven Strategy".) I'll talk more about that in a future blog post.

The History java2perl6api

I've been kicking around various ideas for integrating Java and Perl6/Parrot for years. I think I first decided to use JDBC as the inspiration for the DBI-to-driver API in 2006.

You may remember back in 2004, around the 10th anniversary of the DBI, the Perl Foundation setup a "DBI Development Fund" that people could donate to. I've never drawn any money from that fund. I want to use it to oil other peoples wheels.

In 2007 Best Practical sponsored Perl 6 Microgrants through the Perl Foundation. I asked if I could piggyback my idea for a Java to Perl 6 API translator onto their microgrant management process but using money from the DBI Development Fund. TPF and Best Practical kindly agreed. I posted a description of the task and Phil Crow volunteered and was awarded the microgrant in April 2007.

At OSCON in July 2007 I gave lightning talk called "Database interfaces for open source languages suck" which explained the rationale for using JDBC as a foundation for the DBI-to-driver API and mentioned Phil's java2perl6 project.

Development ground to a halt around the end of 2007 for various reasons. It picked up again for a few months after OSCON 2009 (where I gave a short lightning talk asking for help) then stalled again in October. Partly because we seemed to have hit a limitation with Rakudo and partly because I was focussed on Devel::NYTProf version 3 and then version 4, which took way more time than I expected.

There's life in the project again now. We've dodged the earlier problem, put the code on github, brought it into sync with current Rakudo Perl 6 syntax, and generally instilled some momentum.

The Current java2perl6api

Let's take a look at a simple example.

To generate a perl6 file that mirrors the API of the java.sql.Savepoint class you'd just execute java2perl6api like this:

$ java2perl6api java.sql.Savepoint
loading java.sql.Savepoint
wrote java/sql/Savepoint.pm6 - interface java.sql.Savepoint
checking java/sql/Savepoint.pm6 - interface java.sql.Savepoint

That's loaded and parsed the description of the java.sql.Savepoint class (from the javap command), generated a corresponding perl6 module, and run perl6 to validate it.

The generated module (with some whitespace and cruft removed) looks like this:

use v6;
role java::sql::Savepoint {
    method getSavepointId (
    --> Int   #  int
    ) { ... }
    method getSavepointName (
    --> Str   #  java.lang.String
    ) { ... }
};
=begin pod
=head1 Java
  Compiled from "Savepoint.java"
  public interface java.sql.Savepoint{
      public abstract int getSavepointId() throws java.sql.SQLException;
      public abstract java.lang.String getSavepointName() throws java.sql.SQLException;
  }
=end pod

The pod section shows the description of the class that javap returned. The java2perl6api utility parsed that Java interface and generated the corresponding Perl6 role. The 'java.sql.Savepoint' has been mapped to 'java::sql::Savepoint'. The generated methods are stubs using ... (the "yada, yada, yada" operator). The types int and java.lang.String have been mapped to Int and Str. Because the only types used were built-ins, no type declarations were added.

Currently java2perl6api handles the above plus overloaded methods (which generate multi methods), multiple implements clauses (which generate multiple does clauses). There's also partial support for class/interface constants (which currently generate exported methods).

The default behavior is to recursively process any Java types referenced by the class which aren't mapped to Perl 6 types. So executing java2perl6api java.sql.Connection, for example, will generate 48 Perl 6 modules! (Because java.sql.Connection refers to many types, including java.sql.Array which refers to many types including java.sql.ResultSet which refers to java.net.URL which refers to java.net.Proxy etc. etc.) The --norecurse options disables this behavior.

Normally you'll want to use the recursion but instead of letting it drill all the way into the Java types, you would supply your own 'typemap' specification via an option. That tells java2perl6api which Java types you want to map to which Perl 6 types. So instead of recursing into the java.net.URL type to generate a java/net/URL.pm6 file, for example, you can tell java2perl6api to use a specific Perl 6 type. Perhaps just Str for now.

How this relates to JDBC / DBDI / DBI v2

I want to start applying java2perl6api to the JDBC classes now to create a "Database Driver Interface" or "DBDI" for Perl 6.

Starting with the DriverManager class and the Connection interface I'll use java2perl6api to generate corresponding Perl 6 roles with heavy stubbing out of types. Basically anything I don't need to think about right now will be mapped to the Any type.

I'll start fleshing out some basic implementation logic for each in a Perl 6 class that does the corresponding role. I'll probably use PostgreSQL as the first driver and the guts of MiniDBD::Pg as inspiration.

The first minor milestones will be creating connections, then execute non-selects, then selects then prepared statements. Somewhere along the way I expect they'll be a Perl 6 DBDI driver implemented for the Perl 6 MiniDBI project. The next key step would be to start refactoring the code heavily so anyone wanting to implement a new driver should only have to implement the driver specific parts. (There are some JDBC driver toolkits that can provide useful ideas for that.)

What needs doing

There's a TODO file in the repository that lists the current items that need working on.

One fairly simple item is to add a --prefix option to specify an extra leading name for the generated role. So java.sql.Savepoint with a prefix of DBDI would generate a DBDI::java::sql::Savepoint role.

Another item, less simple but more important, is to automatically discover the values of constants and embed them into the generated file. Probably the best way to do that is to extend the parser (which uses Parse::RecDescent) to parse the verbose-mode output of javap, which includes those details.

There are plenty of others.

How you can get involved

Firstly, come and say "Hi!" in the #dbdi IRC channel on irc.freenode.net.

The code is on github. You can get commit access by asking on the #perl6 channel.

There's also a mailing list at dbdi-dev@perl.org which you can subscribe to.

I look forward to hearing from you!



  1. When I say "Perl 6 has the potential to become a very popular language" I do so with typical British Understatement.


Filed under: perl, software Tagged: dbdi, java, perl, perl6

29 Jul 2010 12:00am GMT

28 Jul 2010

feedPlanet Perl Six

Solomon Foster: A more complete design

Okay, here's what I have at the moment, which passes some basic tests. First, the quad iterator.

class FiniteIntRangeQuadIter is Iterator {
    has $!value;
    has $!max;
    has $!nextIter;

    method infinite() { False }

    method reify() {
        return ($!value,) if $!value ~~ EMPTY;
        unless $!nextIter.defined || $!nextIter ~~ EMPTY {
            if $!value != $!max {
                my $s = $!value + 4;
                $!nextIter =
                    $s < $!max
                        ?? FiniteIntRangeQuadIter.new( :value($s),
                                                       :max($!max) )
                        !! EMPTY;
            } else {
                $!nextIter = EMPTY;
            }
        }
        $!value, $!value + 1, $!value + 2, $!value + 3, $!nextIter;
    }
}

For simplicity and speed, this only works if the number of iterations is divisible by four. So we need some other mechanism to handle the remaining 1-3 elements. Introducing a very simple iterator:

class ConsIter is Iterator {
    has $!value-parcel;
    has $!nextIter;

    method infinite() { $!nextIter ~~ EMPTY ?? False !! $!nextIter.infinite; }

    method reify() {
        &infix:<,>(|$!value-parcel, $!nextIter);
    }
}

This just takes a Parcel and another iterator. When you iterate it, it returns the Parcel first, then the other iterator. The reify method probably could be more efficient, but then, it should only get called once for the entire iteration. Then you just need a way to use the two iterators together:

sub MakeSmartIter($a, $b) {
    return EMPTY if ($b < $a);

    my $mod = ($b - $a + 1) % 4;
    if $mod == 0 {
        FiniteIntRangeQuadIter.new(:value($a), :max($b));
    } else {
        my @parcel-to-be;
        my $i;
        loop ($i = 0; $i < $mod; $i++) {
            @parcel-to-be.push($a + $i);
        }

        my $parcel = &infix:<,>(|@parcel-to-be);
        my $next-iter = $a + $mod < $b ?? FiniteIntRangeQuadIter.new(:value($a + $mod),
                                                                     :max($b))
                                       !! EMPTY;
        ConsIter.new(:value-parcel($parcel),
                     :nextIter($next-iter));
    }
}

There absolutely has to be a better way to build a Parcel, but I wasn't able to figure it out, and this one works. Again, this code only gets called once for the entire iteration. It's probably enough of a speed hit that it should only be used for longer lists; more timing is required to figure out where the sweet spot is to switch over. (Though come to think of it, it's probably worth letting people more familiar with the ins and outs of Parcels go over this code a few times before trying to figure out where that sweet spot is.)

As it stands now, it takes 27.3 seconds to execute 2..10000 in Rakudo. Switching to this iterator, it takes 8.1 seconds. (Note that 2..10000 is the worst case for the slow bits of the new code; 1..10000 shaves a tenth of a second or so off the time.)

It would be fairly straightforward to convert the Range to use this code for Int iteration. The big thing at this point would be generating enough tests for it. This is the sort of code in which off-by-one errors lurk, and this would be a terrible place to let such an error creep into Rakudo.

Update: Thanks to jnthn++, the Parcel-making code is now

        my $parcel := pir::new__Ps('Parcel');
        my $i;
        loop ($i = 0; $i < $mod; $i++) {
             pir::push($parcel, $a + $i);
        }

That ought to be about as efficient as it can get without going entirely into PIR, I think.


28 Jul 2010 2:56pm GMT

feedPlanet Perl

Writing a perl read-eval-print loop (REPL) - part 1

=== update, April 25 For the impatient, part 2 and part 3 are already out and I'm aiming to publish a part per week until I run out of ideas and change to a different topic. === end update, original post follows So, I need to sort out my person...

Read and post comments | Send to a friend

28 Jul 2010 8:45am GMT

Writing a perl REPL part 2 - a history plugin

So, last time we got from scratch to a basically working simple perl REPL. So now it's time to start writing plugins, since currently it's disturbingly basic and only really useful for ... well, for making a blog post about how it works at all :) ...

Read and post comments | Send to a friend

28 Jul 2010 3:39am GMT

feedPlanet Perl Six

Solomon Foster: Optimizing Range Iteration, Part 2

So, continuing from my last post. Here's our starting point for the third round of optimization:

for 1..10000 {
    my $a = $_ + 1;
}

That takes 26.5 seconds. (Note that's already about 10s faster than before optimizing the Int comparisons.)

This requires a more complicated iterator.

class FiniteIntRangeIter is Iterator {
    has $!value;
    has $!max;
    has $!nextIter;

    method infinite() { False }

    method reify() {
        return ($!value,) if $!value ~~ EMPTY;
        unless $!nextIter.defined || $!nextIter ~~ EMPTY {
            if $!value != $!max {
                my $s = $!value.succ;
                $!nextIter =
                    $s < $!max
                        ?? FiniteIntRangeIter.new( :value($s),
                                                   :max($!max) )
                        !! EMPTY;
            } else {
                $!nextIter = EMPTY;
            }
        }
        $!value, $!nextIter;
    }
}

This is basically the current RangeIter with the non-Int bits removed as well as "excludes max" (as that is just the same as iterating to $max - 1 for Ints). Pretty straightforward, and it takes 11.6 seconds to execute.

Unfortunately, returning more than one value at a time is much more complicated for the finite case. Ooo, unless it's not! You can write the iterator to alway go up by two, and then create a special iterator to handle the first iteration if the overall number is odd. We're obviously getting into the realm of tricky code here. But the double iterator approach gets us to 9.5 seconds, and an even crazier quad iterator gets it to 7.8. The code is getting ugly, but it's a big improvement over the our starting point.

What to do with this? Unfortunately, the best of the optimizations are on the tricky side, and code freeze for Rakudo Star is supposed to be in about 15 hours. I'm not terribly comfortable overhauling the Range iteration code this close to the release. On the other hand, 26.5 seconds to 7.8 seconds is a pretty big improvement. And this is a core feature that is likely to be used a lot by people trying out Rakudo for the first time.

I think I'm going to sleep on it.


28 Jul 2010 3:19am GMT

Audrey Tang: Perl 6 十周年慶: Rakudo:白銀年代 (五之四)

(This is a translation of masak++'s excellent Perl 6 anniversary post, part 4 of 5.)
(這是 masak++ 為慶祝"樂土之星"即將正式發行所寫的紀念文章的中譯。)


Pugs 帶來了決定性的變化。隨著唐鳳的「非官方」Perl 6 實作完成度愈來愈高,不少人也開始發展自己的「小規模」實作。

從 2005 年到今天,有十來個「小規模」實作陸續出現,其中不少到現在仍在持續開發。其中有些是為了探索 Perl 6 某部份的設計,也有的是想要實作出整個語言。

(我稱它們為「小規模」,是因為開發者人數較少,使用者也不多的緣故。)

從 Pugs 登場到離場的這兩年多裡,在 Parrot 上實作 Perl 6 的腳步並未稍停。但因為當時 Parrot 還不夠成熟,想要慢慢搭建起編譯器所需的工具鏈,勢必得花上許多時間。

早在 2005 年時,Patrick Michaud 就已著手在 Parrot 上實作文法引擎(PGE)及編譯器工具集(PCT)。到了 2007 年,Patrick 終於得以開始正式實作 Perl 6;這個計劃在 2008 年初命名為 Rakudo(樂土)。

老實說,我是在它取名為「樂土」之後,纔注意到這個計劃的。

Patrick 的願景是這樣的:一個完整的 Perl 6 實作,首先需要有良好的 Perl 6 文法引擎,以及完善的的編譯器工具鏈作為基礎。在完成這兩項計劃之後,Patrick 才轉而開發實際的 Perl 6 編譯器和執行環境。

當時,一位名叫 Jonathan Worthington 的強人不慎答應 Patrick,要在 Rakudo 上實作 Junction(連接值)功能。(後來他纔發現,要實作連接值,得先實作多重分派,而這又得先實作型別系統,所以又得先完成大部份的物件導向系統... XD)

於是在 2008 上半年,Patrick 和 Jonathan 齊心協力,為 Rakudo 寫出了一個接一個的功能。

雖然 Rakudo 並不像唐鳳開發 Pugs 時那樣輕鬆寫意,而且早期版本實作的功能通常漏洞百出,但它確實讓 Perl 6 社群再度活躍起來。

在相對完整但發展停滯的 Pugs 計劃,與緩慢但穩定地追上 Pugs 的 Rakudo 計劃之間,我逐漸把注意力轉向後者。

2008 年的夏天過得很快;我和 viklund 合作,用當時還乳臭未乾的 Rakudo 寫一套圍紀引擎(純粹為了好玩而已)。

我們對自己說,如果竟然能寫出來,那我們就到 YAPC::EU 會議上,以它為主題來一場閃電演講。

嗯,最後我們真的寫出來了,也真的到 YAPC::EU 講了一場。與會者聽到有人能用 Perl 6 寫網站程式,反應十分熱烈,我們也很開心。

可是,中間我們繞了多大的彎,避開了多少還沒實作的功能,又發現了多少瑕疵啊!

而且,既然這是個秘密計劃,我們就不能在 #perl6 上直接貼出有問題的程式。要回報瑕疵之前,我們得先把代碼清理到看不出和圍紀有任何關係纔行。在那段時間裡,我學會了在瑕疵回報上打高爾夫(Golfing,壓縮字數)的價值。

那年夏天,我提交了許多瑕疵回報,每份的代碼都清理過了。就像小孩子收集瓶蓋一樣,我開始熱衷於此。

當時 Rakudo 的瑕疵不少。有一陣子,瑕疵似乎無所不在。這不能怪 Patrick 和 Jonathan;他們一直都很盡責。但任何專案都要經歷實地運用的考驗,而 viklund 和我恰好是首先拿 Rakudo 來用的人。

實地測試和回報瑕疵成了我的嗜好,驅使我不斷重複著「拿 Rakudo 做些新鮮事」、「看 Rakudo 爆炸」、「寫瑕疵報告」的無盡迴圈。

能脫離粉絲階段,正式參與開發,這讓我非常高興。日後我寫了更多 Perl 6 代碼,甚至還拿到了 Rakudo 的提交權... 但我想我會一直當那個「專門提瑕疵報告的傢伙」吧。

目前頻道上的幽默以大笑貓(lolcat)、奇特的顏文字,以及其他時下的網路流行語彙。頻道上的氛圍輕鬆有趣;大笑貓和編譯器內核開發的對比,時常令人耳目一新。

<pmichaud> 早安, #perl6
<jnthn> 早, pmichaud
<PerlJam> pm 你好
<colomon> o/
<mathw> o/ pmichaud
<moritz_> /o/
<mathw> \o\
<jnthn> \o/ |\o/| o< /o\
<jnthn> ;-)
<mathw> 啊啊啊啊
* mathw 躲起來
<okeCay> o/\o !

隨著 Rakudo 漸趨成熟,「綱要」也隨之作出修訂。也許有人覺得這很可怕。要怎樣去學一門不斷變化的語言呢?為什麼不讓規範文件確定下來呢?

我個人的想法是:我不希望語言規範被「鎖定」或「凍結」住,因為目前的修訂已經愈來愈小,大都是為了修正 Rakudo 等實作回報出的問題。

雖然 Perl 6 的規格改動幅度超過我所知的其他語言,但另一方面,它也一天天變得更加穩定。我們稱它為「漩渦式開發模型」,實作和規範雖然相互影響,但最終仍是往同一個單點收歛。

相對於某些 IRC 頻道的粗暴文化,#perl6 可說是網路上最親切的地方之一。我們花非常多的時間回答新手的問題、幫忙修正語法錯誤、並為訪客和開發團隊釐清各式術語及設計方針。我們互相幫忙看代碼和網誌文章,讓頻道上洋溢著彼此尊重和互相照顧的感覺。

今天的 #perl6 幾乎是「日不落頻道」,擁有來自全球各地的人積極參與。我們不僅覺得這裡有個非常酷、足以向世界展示的語言,也很自豪於 Perl 6 文化的良好素質。

2008 年以來,Rakudo 逐漸領先其他實作,完成度甚至超越了 Pugs。目前絕大多數的算符和控制結構都已完工,更有強大的正規表示式與文法引擎(感謝 Patrick!)以及優秀的物件導向、多重分派支援(感謝 Jonathan!),許多其他功能也已充份實作。

我們還有許多「小規模」的 Perl 6 實作,幫忙推動「綱要」發展和探索實作策略。但投注於 Rakudo 開發的人力,確實遠大於其他實作。Rakudo 每月釋出新版的工作人員名單,通常都在二三十人以上。

重新回到「Perl 6 每天都更近一些」的日子真好。

我仍然每天回報一則 Rakudo 的瑕疵,但通常是關於尚未實作的進階語言特性,而不是缺少什麼常用的功能。

2009 年至今,Rakudo 成功完成了幾項龐大的重構任務。首先是文法系統,隨後其他各元件也都分別重新寫過。

對開發者來說,這些小計劃統合成了所謂的「Rakudo 大重構」。

對於外界來說,這就是即將正式發表的 Rakudo Star,「樂土之星」。

28 Jul 2010 2:32am GMT

Solomon Foster: Optimizing Range Iteration

I wasn't planning on doing any more work on Rakudo before Rakudo Star, but the conversation on #phasers today got me thinking. On the one hand, I'm somewhat opposed to the idea of the Range-specific RangeIter iterator, as Range and the series operator are supposed to behave identically. On the other hand, the idea of creating a special case for RangeIter to handle the super-common Int iteration case seemed very appealing. So I thought I'd poke around a little and see what I could do.

I'm going to tell this story backwards of the way I actually did it, because I flailed around a lot at the beginning. My goal was to focus on a construct like

for 1..10000 {
   # do something
}

But in the process of my flailing, I thought that switching from before to < made the code go slower, so I thought I might focus on that.

So here's the first bit of code I'm going to talk about optimizing:

my $i;
loop ($i = 0; $i < 10000; $i++) {
    my $a = $i + 1;  # this line just to give the loop something to do!
}

That took 7.4 seconds to execute on my MacBook Pro. Much faster than a loop using 1..10000, but still awfully slow.

Well, < didn't have a specific version for Int. It relied on the Real version to convert the arguments to Num and delegate to that version of <. It was very easy to code up an Int specific version of < which calls down into PIR. And with that in place, the above code runs in 4.0 seconds. So, this simple change pretty much doubles the speed of the most basic loop. (That time includes Rakudo's start up, after all.)

So, sort of the next logical step turns out to be to look at the infinite case. Let's look at a slightly different piece of code:

for 1..* {
    last if $_ > 10000;
}

That takes 19.1 seconds on my MBP. So, here's a new iterator type crafted specifically for infinite Ranges:

class InfiniteIntRangeIter is Iterator {
    has $!value;
    has $!nextIter;

    method infinite() { True; }

    method reify() {
        unless $!nextIter.defined {
            $!nextIter = InfiniteIntRangeIter.new( :value($!value.succ) );
        }
        $!value, $!nextIter;
    }
}

Using that instead of the default RangeIter completes the above sample loop in 10.6 seconds.

But wait! pmichaud says iterators will be more efficient if they return more than one value at a time. Basically, the above version constructs an iterator object for each iteration. If we return two values at a time, we can cut the number of objects created in half. Seems like that ought to be a win. Here's the new source:

class InfiniteIntRangeIter is Iterator {
    has $!value;
    has $!nextIter;

    method infinite() { True; }

    method reify() {
        unless $!nextIter.defined {
            $!nextIter = InfiniteIntRangeIter.new( :value($!value + 2) );
        }
        $!value, $!value + 1, $!nextIter;
    }
}

That's 9.5 seconds, another 10% shaved off. Returning four values at a time gets it to 8.7 seconds. Eight gets us 8.2 seconds, and it seems like we are into diminishing returns.

But wait! The loop code uses >, which I haven't optimized yet. Switch it to use the already optimized <, and the runtime is down to 4.8 seconds. Seems like fine progress!

This blog post is probably already too long, so I'll stop it short here.


28 Jul 2010 2:27am GMT

feedPlanet Perl

Perl is ready for HTML5

A lot of amazing HTML5 applications built with Mojolicious and Perl have recently popped up.

This screencast contains a little preview for an upcoming SSH client built by vti running right in your browser, communicating through WebSockets with a Mojolicious server in the background.

You can actually try the IRC client shown in the screenshot above at http://dev.xantus.org and say hello to us, it was built by xantus to showcase ExtJS, Mojolicious and cross browser WebSockets. (Code on GitHub)

Time to get as excited about HTML5 as we are! :)

Permalink | Leave a comment »

28 Jul 2010 12:45am GMT

27 Jul 2010

feedPlanet Perl

Lazy Database Columns and Virtual Vertical Partitioning

Recently we were trying to fix a database performance issue and I had to hit the DBIx::Class irc channel for some advice. Specifically, mysql has an issue where a query with text or blob columns forces a disk sort under certain conditions. Suffice it to say, we hit those conditions with several text columns and benchmarking certain queries showed that removing those columns from a query significantly sped up said queries. That, unfortunately, is a bit tricky under DBIx::Class, but Matt Trout made an excellent suggestion which I later implemented. Why not do a virtual vertical partition of our tables?

Here's a simple package pulled straight from the DBIx::Class docs:

package MyDB::Schema::Result::Artist;
use base qw/DBIx::Class::Core/;

__PACKAGE__->table('artist');
__PACKAGE__->add_columns(qw/ artistid name /);
__PACKAGE__->set_primary_key('artistid');
__PACKAGE__->has_many(cds => 'MyDB::Schema::Result::CD');

1;

Now imagine that the artist table also has huge "biography" and "artistic_vision" columns defined as "TEXT" (in the database, but not shown in the package):

package MyDB::Schema::Result::Artist;
use base qw/DBIx::Class::Core/;

__PACKAGE__->table('artist');
__PACKAGE__->add_columns(qw/ artistid name biography artistic_vision /);
__PACKAGE__->set_primary_key('artistid');
__PACKAGE__->has_many(cds => 'MyDB::Schema::Result::CD');

1;

In mysql, if you create a query which tries to use the MEMORY storage engine, the TEXT columns will force a disk sort, no matter how little data you pull. Thus, you want to avoid pulling those TEXT columns, but it's a bit tricky. Class::DBI allowed you have lazy columns and they looked like this:

__PACKAGE__->columns(Primary   => qw/artistid/);
__PACKAGE__->columns(Essential => qw/name/);
__PACKAGE__->columns(Others    => qw/biography artistic_vision/);

Now if you fetch an artist, you only get the large columns when you request them for an individual result. This means that complex queries could be much faster. However, it also means that if you return 100 artists with one query and you need those extra fields, you have at least 101 SQL calls because you'll fetch those once per object.

We tried a different approach. It's perfectly OK to have more than one result class point to the same table, so we create a "Lazy" result class:

package MyDB::Schema::Result::Artist::Lazy;
use base qw/DBIx::Class::Core/;

__PACKAGE__->table('artist');
__PACKAGE__->add_columns(qw/ artistid biography artistic_vision /);
__PACKAGE__->set_primary_key('artistid');

1;

And we remove the original columns and proxy across:

package MyDB::Schema::Result::Artist;
use base qw/DBIx::Class::Core/;

__PACKAGE__->table('artist');
__PACKAGE__->add_columns(qw/ artistid name/);
__PACKAGE__->set_primary_key('artistid');
__PACKAGE__->has_many(cds => 'MyDB::Schema::Result::CD');
__PACKAGE__->has_one( lazy_columns => 'MyDB::Schema::Result::Artist::Lazy',
    undef,
    { proxy => [qw/biography artistic_vision/] }
);

1;

Queries against the Result::Artist will simply skip the TEXT columns. The proxy ensures that we have transparent read behaviour (we overrode new() and insert() for the write behaviour).

At this point you're saying "but Ovid, that's just as bad as the Class::DBI model!", and you'd be right. Except there's a curious artifact to our code which lets us work around that.

We do not pass result or resultset objects to our views. Instead, we extract the data into something we call blocklists which is effectively a read-only view on that data. This was done in the good-ol-days when didn't want to risk our front-end people being able to make additional SQL queries from the view. Thus, I modified the blocks in the blocklists to not fetch any "lazy" data. Then, before we pass the blocklist to the view, we call "finalize" on it. I wrote something which looks like this:

sub finalize {
  my $self = shift;

  my %blocks_to_complete;
  my @fifo_blocks = $self->blocks;
  # Walk the blocklists and collect all incomplete blocks
  while ( my $block = shift @fifo_blocks ) {
    for my $attr ( $block->block_attributes ) {
      $block->can( $attr ) or next;

      my $value = $block->$attr;
      if ( $value->isa('BlockList') ) {
        push @fifo_blocks => $value->blocks
      }
    }
    next if $block->is_complete; # don't reprocess
    my $lazy_model = $block->lazy_model;

    $blocks_to_complete{ $lazy_model }{ $block->id } ||= [];
    push @{ $blocks_to_complete{ $lazy_model }{ $block->id } } => $block;
  }

  # Walk the lazy classes, fetch the resultsets and populate the blocks
  for my $lazy_model ( keys %blocks_to_complete ) {
    my $blocks_for_id = $blocks_to_complete{ $lazy_model };

    my @ids = keys %$blocks_for_id;
    my @lazy_dbic_rows = Dynamite->model( $lazy_model )->search(
      { id => { -in => [ @ids ] } },
    )->all;

    for my $lazy_dbic_row (@lazy_dbic_rows) {
        # add the lazy data to the blocks
    }
  }

  return 1;
}

Note how we fetch all of the ids for a given block type and rather than make a separate SQL call for each block, we fetch all of the lazy data with one "id IN" query.

I call this "virtual vertical partitioning". We've effectively split each table with problematic data in two and if we physically partition these tables (there are compelling reasons for us not to), we merely need to switch the table name in the "Lazy" class and everything should just work.

Next, I want to push our "created" and "modified" columns into the Lazy classes. They're almost useless, but I've abstracted things out enough that this should be an almost transparent change.

27 Jul 2010 3:23pm GMT

Perlbuzz news roundup for 2010-07-27


These links are collected from the Perlbuzz Twitter feed. If you have suggestions for news bits, please mail me at andy@perlbuzz.com.

27 Jul 2010 2:50pm GMT

Why roles in Perl are awesome

by Chris Prather

A question came up recently on a mailing list. I was talking about how Roles are a awesome win for Perl5 considering how few languages implement the concept1. Someone asked what the win was with Roles. I happen to have been thinking about this recently and dashed off a reply.

When you use Inheritance, especially multiple inheritance, for behavioral re-use you run into several problems quickly.

First Inheritance is an explicit modeling of a relationship that carries semantic meaning. Let's say you're developing a game for Biology students to explain to them taxonomy. In this game a Dog class is a subclass of Animal. That is, the Dog class inherits specific behaviors and attributes from the Animal class. This probably isn't even a direct relationship your Dog class may inherit from a Mammal class which inherits from a Vertebrate class which inherits from Animalia which itself inherits from Life. These kinds of hierarchies are common in Taxonomy as well as in Object Oriented programming. However when you need to express something that may cross cut concerns in, you run into issues.

Say for example your marketing department has had trouble selling this product to schools and is attempting to market to parents directly. They have done studies and kids really like Pets2. So your boss comes to you because the company wants you to add the concept of Pet to your Taxonomy model.

Pets don't fit into a Taxonomy, it's obvious that not all Animalias are Pets3 and some Pets may not be animals at all4. In many languages can use Multiple Inheritance to describe this new "I'm an Animalia and a Pet" relationship but often you run into issues there as well. Is a Pet a Life? That would mean our object model would look like:

Life
    Animalia
        Vertebrae
            Canine    Pet
                Dog

Pet stands out like a sore thumb. Obviously we've got issues with this new modeling. We talk to our boss and figure out that the rules for Pet are simple. Pet's are always domesticated versions of the Animalia, but not every class in Animalia is a pet. So for example Dogs are always Pets, Wolves are not. We can solve this with multiple inheritance now, but it's really not a clean way to express the relationship and it requires us to document the special relationship the Pet class would have with the rest off the Inheritance tree. Once you get beyond a few "special cases" like this it becomes hard to see the model for the exceptions.

This is why some languages like to disallow multiple inheritance entirely. In Java for example, Pet could become an Interface.

public interface Pet {
    Date getYearDomesticated;
}

This however means that every class that we want to be a pet needs to have the exact same piece of boiler plate code added to it.

class Dog implements Pet {
    ...
    private Date yearDomesticated;
    public Date getYearDomesticated () { this.yearDomesticated }
    ...
}

If we instead have the concept of Roles then we can apply the concept of a Pet once at any level of the hierarchy we need. A example using a modern Perl5

package Pet {
    use Moose::Role
    has year_domesticated => (
        is => 'ro',
        isa => 'DateTime',
        required => 1
    );
}

package Dog {
    use Moose;
    extends qw(Canine);
    with qw(Pet);
}


The Pet Role here implements everything we need for a default implementation, and doesn't require more boiler plate to our Dog class, that the bare minimum needed. It also avoids the ugly inheritance issues we saw with multiple inheritance by moving the behavior composition onto different tool. In my opinion, Roles aren't a win for every use of inheritance, nor for every time you want to re-use behavior, but they are an excellent tool to have in the box and one that the Moose crowd knows to reach for quite often.


  1. Off the top of my head I only know about Perl5, Perl6, Scala, Javascript, and Smalltalk. There may be other implementations out there.

  2. The Marketing guy's daughter plays on WebKinz nightly.

  3. Pet Shark's would be dangerous to say the least, and where would you keep a pet Blue Whale?

  4. Who doesn't love their Pet Rock?

  5. We're using the the inline package syntax that will be released in 5.14

Chris Prather is an Owner at Tamarou LLC, a member of the Moose cabal, and responsible for Task::Kensho.

27 Jul 2010 2:34pm GMT

perlprogramming.org looking for a nice home

I picked up this domain name a while ago since it was available and people were saying how Perl needs better visibility. (I was probably inspired by Tim's post about TIOBE). Currently, I just redirect to perl.org. The domain is coming up for renewal and I'll gladly sign it over to someone who can make a good case for what they plan to do with it to benefit the perl community.

27 Jul 2010 4:33am GMT

26 Jul 2010

feedPlanet Perl

Links for 2010-07-26

26 Jul 2010 10:05pm GMT

25 Jul 2010

feedPlanet Perl Six

Moritz Lenz (Perl 5 to 6): Currying

NAME

"Perl 5 to 6" Lesson 28 - Currying

SYNOPSIS

  use v6;
  
  my &f := &substr.assuming('Hello, World');
  say f(0, 2);                # He
  say f(3, 2);                # lo
  say f(7);                   # World
  
  say <a b c>.map: * x 2;     # aabbcc
  say <a b c>.map: *.uc;      # ABC
  for ^10 {
      print <R G B>.[$_ % *]; # RGBRGBRGBR
  }

DESCRIPTION

Currying or partial application is the process of generating a function from another function or method by providing only some of the arguments. This is useful for saving typing, and when you want to pass a callback to another function.

Suppose you want a function that lets you extract substrings from "Hello, World" easily. The classical way of doing that is writing your own function:

  sub f(*@a) {
      substr('Hello, World', |@a)
  }

Currying with assuming

Perl 6 provides a method assuming on code objects, which applies the arguments passed to it to the invocant, and returns the partially applied function.

  my &f := &substr.assuming('Hello, World');

Now f(1, 2) is the same as substr('Hello, World', 1, 2).

assuming also works on operators, because operators are just subroutines with weird names. To get a subroutine that adds 2 to whatever number gets passed to it, you could write

  my &add_two := &infix:<+>.assuming(2);

But that's tedious to write, so there's another option.

Currying with the Whatever-Star

  my &add_two := * + 2;
  say add_two(4);         # 6

The asterisk, called Whatever, is a placeholder for an argument, so the whole expression returns a closure. Multiple Whatevers are allowed in a single expression, and create a closure that expects more arguments, by replacing each term * by a formal parameter. So * * 5 + * is equivalent to -> $a, $b { $a * 5 + $b }.

  my $c = * * 5 + *;
  say $c(10, 2);                # 52

Note that the second * is an infix operator, not a term, so it is not subject to Whatever-currying.

The process of lifting an expression with Whatever stars into a closure is driven by syntax, and done at compile time. This means that

  my $star = *;
  my $code = $star + 2

does not construct a closure, but instead dies with a message like

  Can't take numeric value for object of type Whatever

Whatever currying is more versatile than .assuming, because it allows to curry something else than the first argument very easily:

  say  ~(1, 3).map: 'hi' x *    # hi hihihi

This curries the second argument of the string repetition operator infix x, so it returns a closure that, when called with a numeric argument, produces the string hi as often as that argument specifies.

The invocant of a method call can also be Whatever star, so

  say <a b c>.map: *.uc;      # ABC

involves a closure that calls the uc method on its argument.

MOTIVATION

Perl 5 could be used for functional programming, which has been demonstrated in Mark Jason Dominus' book Higher Order Perl.

Perl 6 strives to make it even easier, and thus provides tools to make typical constructs in functional programming easily available. Currying and easy construction of closures is a key to functional programming, and makes it very easy to write transformation for your data, for example together with map or grep.

SEE ALSO

http://perlcabal.org/syn/S02.html#Built-In_Data_Types

http://hop.perl.plover.com/

http://en.wikipedia.org/wiki/Currying

25 Jul 2010 6:17pm GMT

24 Jul 2010

feedPlanet Perl Six

Solomon Foster: Vector.pm working again

I went to announce on #perl6 that I had Last of the Careless Men's Vector class running on modern Rakudo (finally), and literally in the middle of typing the announcement there was a massive net spasm of some sort and I was kicked off the channel. Sigh.

Anyway, thanks to a timely patch from jnthn++ and a bit of rearranging things on my part, Vector.pm works again, or at least passes all the current tests in its 01-basic.t. I will try to get the rest of the code in that package working again in time for R*. The only major caveat at this point is that the op= metaoperator does not work for the Vector-specific operators. Apparently this is because of a known bug.


24 Jul 2010 7:24pm GMT

Gabor Szabo: Happy 2nd birthday to Padre - Get on an IRC channel

The IRC redirector on the Padre website. Type in some username and select the channel.

If your perl related channel is missing from the list let us know on #padre irc.perl.org

I hope you'll come by the Padre channel and say happy birthday to the developers!

Direct link to the screencast

24 Jul 2010 3:55pm GMT

Gabor Szabo: Happy 2nd birthday to Padre - Get on an IRC channel

The IRC redirector on the Padre website. Type in some username and select the channel.

If your perl related channel is missing from the list let us know on #padre irc.perl.org

I hope you'll come by the Padre channel and say happy birthday to the developers!

Direct link to the screencast

24 Jul 2010 3:55pm GMT

Audrey Tang: Perl 6 十周年慶: Pugs:黃金年代 (五之三)

(This is a translation of masak++'s excellent Perl 6 anniversary post, part 3 of 5.)
(這是 masak++ 為慶祝"樂土專案"即將正式發行所寫的紀念文章的中譯。)


我還記得初次踏入 #perl6 頻道的感覺。

有人真的拿「綱要」來實作,這已經夠驚人了。而唐鳳又是個極富生產力的黑客,像磁鐵一般,以前所未見的速度吸引眾人投入開發。

待在 #perl6 頻道上,就像是站在颱風眼附近;事情像奇蹟般陸續發生,無論是因為唐鳳又完成了一組更動,或是旁邊又有人開始了某個很酷的專案。有趣的想法和點子,日夜不停湧入頻道當中。

而我們所有人都真的在跑(早期的)Perl 6!算符、副程式、類型、多載... 一個接著一個,我們期待以久的功能陸續開始運作。

很快,我們就寫出了在頻道上即時運行 Perl 6 代碼的機器人。

無論是誰,只要一提出改進 Perl 6 的想法,唐鳳就送他一個提交權。這招還真管用!數以百計的人獲得了提交權,卻完全沒有像圍紀系統上常見的破壞行為出現。許多人踴躍加入,主動做出貢獻。

當時我們的口號是「信任安那其」,現在回想起來仍然很聳動。

唐鳳興高采烈地站在漩渦中心,引導大家發展各式相關計劃,幾乎每天都邊寫網誌,邊提交出鉅量的代碼,為逐漸成形的 Perl 6 社群注入活力。

Pugs 是用 Haskell 寫成的,因此早期 #perl6 的文化深受 Haskell 文化的影響。

Pugs 黑客團隊的綽號是「浪達駱駝(Lambdacamels)」;頻道上大量出現資訊科學類的的論文、關於 Haskell 的書藉,以及其他編程相關的深奧論著。這些參考書目今天仍然可以在 Pugs 的 READTHEM 文件裡看到。

頻道上的幽默相當機智,主題往往也和電腦有關。

<audreyt> Alias_:我的眼鏡是 style="border: none"
<Alias_> 無所謂
<Alias_> 人眼的感光邊界會自動加上 border: solid 1px #9999
<audreyt> 說得對
<audreyt> 不過以我的視力來說,更像是 ridged
* audreyt 望著頻道上的高度技客傾向嘆氣
...
<audreyt> 這顯然要 blame malaire++
<audreyt> 我的意思是 praise
<audreyt> 不然說 annotate 好了

頻道上主要的感嘆詞是「讚!(woot!)」。主要說「讚!」的人是唐鳳。業力(Karma)取代了貨幣,由機器人在頻道上統計,並在即時公佈提交訊息時,一併幫提交者加分。

我要說明一點:當時在 #perl6 上,我只是個粉絲。我對 Pugs 沒有作出什麼重大貢獻,對「綱要」和語言設計也沒有幫上什麼忙。至於在頻道上搞笑嘛,我倒是不遺餘力。:-)

2005 年 3 月,我的傻言傻語換來了一份提交權:

<autrijus> 歡迎上船!
<masak> 謝謝。因為 Pugs 的關係,我幾乎整晚沒睡。:-)
<autrijus> 開心嗎?
<masak> 太興奮了
<autrijus> 這感覺我懂 :)))

唐鳳保持著很高的開發速度,頻道上經常出現關於他生產力的玩笑:

<autrijus> 待會見 - 洗澡去 &
<geoffb> 所以說唐鳳在浴室連 IRC 的謠言不是真的嘍...
<geoffb> 也許他把筆記型電腦放在浴簾外,邊洗邊看螢幕。
<autrijus> 沒錯。
<autrijus> 通常是這樣。
<autrijus> 我都拿牙刷按鍵盤,以免鍵盤進水。
<geoffb> *大笑*
...
<Juerd> 每本講 Perl 6 的書都太舊了。
<Juerd> 它們送印後兩小時就過時了。
<Juerd> 等它們進到書店,已經過期一個月了。
<Juerd> 等你買到書準備看時,autrijus 已經把 Perl 6 實作出來了。:)
<mauke> 在睡夢裡實作的!
<castaway> autrijus 會睡覺?
<nothingmuch> castaway: 有時候他宣稱自己去睡了。
* castaway 完全不信
<mauke> 也許他和電腦之間有神經界面,讓他在夢裡寫程式。
<castaway> 這我一點都不意外 :)
<Juerd> castaway: 嗯,有時後他說要去睡,可是沒幾個小時後
              就出現了一大份提交。所以我才不信呢。:)
<castaway> 嘻嘻
<castaway> 據我看來,他每次最多只睡 30 分鐘。
<Juerd> 我想他有超線程功能。

唐鳳曾經說過:「人們以為我是了不起的程序員,但其實是 Haskell 和 Parsec(Haskell 的剖析結合函式庫)太強大了。」不過,這並沒有讓人們停止議論他的產能。

2006 年的某一天,Larry Wall 加入了 #perl6 頻道。他再也沒有離開過。

<avar> ?eval <物美 迅速 價廉>.pick(2)
<evalbot_r16148>("物美", "價廉")
<TimToady> 這是在說我們沒錯...

不過,我們確實失去了唐鳳。在他進入跨性別旅程後,產量雖然有增無減,但在 2007 年一次艱難的重構任務中,唐鳳突然爆發急性肝炎,於是離開了頻道,再也沒有回來。

Pugs 中斷開發。在唐鳳離開後,頻道頓時安靜了許多。

Pugs 還在,但已不再更新,也還沒完全達成對 Perl 6 規格的實作。社群裡的成員都在,但核心人物卻消失了。

當時我不知道未來會如何,只好盼望有更多像 Pugs 一樣的計劃出現。

(唐鳳沒有回頻道的原因,直到兩年之後才在他的一篇網誌裡揭曉。)

24 Jul 2010 6:53am GMT

23 Jul 2010

feedPlanet Perl Six

Gabor Szabo: How to connect to the #perl6 IRC channel and try Perl 6 on-line

Direct link to the screencast

See more Perl 6 entries.

web interface to Freenode. Pick some username and type in the name of the channel: #perl6

23 Jul 2010 5:45pm GMT

Gabor Szabo: How to connect to the #perl6 IRC channel and try Perl 6 on-line

Direct link to the screencast

See more Perl 6 entries.

web interface to Freenode. Pick some username and type in the name of the channel: #perl6

23 Jul 2010 5:45pm GMT

Gabor Szabo: Perl 6 screencast - part 4 - files

Direct link to the Perl 6 files screencast

See more Perl 6 entries.

Perl 6 Code examples

Reading in all the lines of a file in a single scalar using the slurp function:

  use v6;

  my $content = slurp "text.txt";
  say $content.chars;


Reading in all the lines of a file into the first element of an array using the slurp:

  use v6;

  my @content = slurp "text.txt";
  say @content.elems;
  say @content[0].chars;

Reading in all the lines, each line in a separate element of the array using the lines function:

  use v6;

  my @content = lines "text.txt";
  say @content.elems;
  say @content[0].chars;

Iterating over the lines one by one. lines is evaluated lazily here:

  use v6;

  for lines "text.txt" -> $line {
    say $line.chars;
  }

Opening a file using the open function. Reading in one line using the get method. Iterating over the rest of the file using the lines method:

  use v6;
  my $fh = open "text.txt";

  my $first_line = $fh.get;
  say $first_line;

  for $fh.lines -> $line {
    say $line.chars;
  }


Opening a file for writing, printing a string to it using the say method and then closeing it to flush all the buffered output. Then re-reading the file just to show what happened.

  use v6;

  my $fh = open "out.txt", :w;
  $fh.say("text 4");
  $fh.close;

  say slurp "out.txt";



23 Jul 2010 2:05am GMT