We had another TechSocial Meeting in Vienna - taking place on 1st monday of every month. First Willy showed using Perl for emulating heavy (really tons of) hardware - very impressive. Second talk by domm was an intro to Perl 5.10.
The pub (remember TechScocial) did e.g. provide 'Perlhuhnbrust' on the menue, but we didn't ask if it were of the 5.10 persuasion.
The smart match operator lead to immediate discussion, whether there exists a 'not-smart-operator' or rather a 'smart-not-operator' or their combination:
$foo !~~/bar/; # not smart aka dumb match
Would this maybe match every chicken or rather not?
$foo ~!~/bar/; # smart no match
$foo !~!~/bar/; # no dumb match
... which immediately lead to a discussion of the orthogonality of the not operator, which generally was considered as very important. E.g. is this valid syntax, and what does it mean:
not my $var;
Semantically it's a promise not to use this variable in that scope. But perl has a different POV
$ perl -Mstrict -Mwarnings -le'not my $var'
Useless use of not in void context at -e line 1.
OTOH
$ perl -Mstrict -Mwarnings -le'print not my $beer'
1
$ perl -Mstrict -Mwarnings -le'print ! my $beer'
1
... there are some 'true' items, which aren't your beer. But
$ perl -Mstrict -Mwarnings -le'print $_->ignore for not our @beer'
Can't call method "ignore" without a package or object reference at -e line 1.
... you can't actually ignore all of them.
As outlined in the previous journal entry, I'm writing a new presentation tool using Parrot. It now has hit the parrot svn repository.
A basic presentation (written in html) about P3 itself can be found here (sorry - the svn server is delivering this as text/plain).
Above subject is shamelessy stolen from Jonathan, who has used it on IRC. Anyway, I got bored by doing my presentations with
$./parrot slpod.imc yapc.pod
... or some such. I wrote the predecessor of that at YAPC::EU::2003 during lunch break and the slides at dinner (no, that isn't a joke) and it caused a lot of fun at these days.
But in recent times all has to be AJAX, hasn't it? Alas, I started hacking examples/io/httpd.pir to support a CGI GET request, which is invoking Parrot subroutines, and put together 60 lines of JavaScript dealing mainly with keyboard requests to navigate between slide pieces and to send XMLHttpRequests. The XML thingy is totally optional, don't be afraid, plain text messages or html snippets are working fine too - and that's what the next slide presentation program will use.
Given that your GET request delivers a valid HTML snippet, and you got e.g. <div id="answer"></div> on your html page, then all you need to fill this with contents is mainly this JavaScript two-liner:
var x = document.getElementById('answer');
x.innerHTML = req.responseText;
That's almost it. I'll put together a working example in the parrot repo during the next days.
About 10 (more or less) parrots flocked together in the lobby of Jury's Inn Hotel at Wednesday. The topics were:
Parrot provides two opcodes to branch on the truthness of a
register: if and unless. It looks
like that it's just a matter of taste, which one to use. Is it
really?
Not with modern CPUs with branch prediction rules and
with JIT code inside tight inner loops. Below are two versions
of the ackermann function, one written with if
and one using unless. (If you are missing the
loop in the code, well, that's coming from tailcall
optimization, turned on with -Oc.)
$ cat ack-if.pir
.param int x
.param int y
if x goto a1
inc y
.return (y)
a1:
if y goto a2
dec x
.return ack(x, 1)
a2:
dec y
y = ack(x, y)
dec x
.return ack(x, y)
$ cat ack-unless.pir
.param int x
.param int y
unless x goto a1
unless y goto a2
dec y
y = ack(x, y)
dec x
.return ack(x, y)
a1:
inc y
.return (y)
a2:
dec x
.return ack(x, 1)
And here are the timings of both with./parrot -Oc -Cj ack-xx.pir 12
on an AMD X2@2000:
ack-if 2.9 s
ack-unless 2.4 s
Branches with positive branch offsets (downwards) are considered to be likely
not taken, that is the fall-through case is the default one. As there are a lot
more positive numbers than the one zero, the unless is the better choice
here (for some CPUs, YMMV). Well, that's at least my
conclusion for now. But there is another issue: branch
alignment. I've not yet experimented with
different label alignments, but I know that alignment can
cause timing differences like above too.
Heureka - from the -Ofun department
Or - running the ackermann function (and possibly other recursive functions) really fast.
$ time
Ack(3, 11) = 16381
real 0m0.567s
user 0m0.559s
sys 0m0.008s
$ time
Ack(3,11): 16381
real 0m0.980s
user 0m0.978s
sys 0m0.002s
The latter is optimized C code. Parrot is recompiling (or will do when that's finished) statically known and simple PIR code to native machine code via it's JIT system.
See also a recent post on perl6-internals.
Numerous folks contributing more than 640 revisions were helping to create a more powerful bird err parrot.
Thanks all!
Numerous people have contributed to another major release of Parrot: 0.4.0 'Luthor' is out - thanks to all.
The release name is of course not related to this article, but comes from our brand new lexical stuff.
Today I've checked in the final fix for one of the longest outstanding bugs inside Parrot.
A short recap:
Having first-class continuation objects is one of the design goals of Parrot. A lot of HLLs support continuations with some special syntax and with continuations in the core a lot of HLL control structures and features like exceptions can be implemented easily.
But there was a problem with continuations. Continuations can change the CFG (control flow graph) of a program in such a way that there are suddenly loops, where the register allocation code isn't (and can't be) aware of it.
The following code piece from a test provided by Piers revealed the whole problem:
arr1 = "[1, 3, 5]"
arr2 = "[1, 5, 9]"
x = choose(arr1)
y = choose(arr2)
if (x * y != 15)
fail = find_lex "fail"
fail()
To the register allocator this looks like a linear control flow,
which is just executed once (there is no loop outside of that code
snippet). But actually the choose closures are capturing
their continuations and are backtracking through the call to the
fail function. We suddenly have a loop going from
fail() to one of the choose() function
call returns. The code that the register allocator should have been
considering would be something like this:
arr1 = "[1, 3, 5]"
arr2 = "[1, 5, 9]"
choose_again_1: # label actually in front of function return
x = choose(arr1)
choose_again_2:
y = choose(arr2)
if (x * y != 15)
fail = find_lex "fail"
fail()
goto choose_again_1 or _2
This implies that the registers
of the variables x, y, arr2 can't be reused for example to
assign a register to the fail variable. But exactly this
has happened and the code really "fail"ed.
There were some (IMHO) impractical proposals to fix this, like refetching all variables from lexicals all the time (and don't use native integers and numbers because these aren't lexicals) but the real fix for this is now in: that is - just don't reallocate the registers used by lexicals and non-volatile variables to other variables like temporaries.
That's the reason for variable-sized register frames and, well, some lack of visible progress of Parrot development for some time.