Feeds:
Posts
Comments

Switching to WP8

My Android Background

I’ve owned a HTC Desire for almost 3 years (100 years in dog smartphone years) and it has been quite an experience.

  • It was never particularly brilliant at being a phone. Calls would often drop, or never make it through at all.
  • The Desire had a bug that meant that replying to an SMS sometimes sent your response to someone else. If you had a mistress, I imagine that could have lead to some difficult conversations… :)
  • The amount of storage for apps was ridiculously limited. It was supposed to be 512MB, but somehow HTC managed to reduce that to 147MB. There are a few ways around this limitation.
  • The last official OTA update was to 2.2 – Froyo. Yup, not even Gingerbread. The official (7.2) Cyanogenmod release did get you to 2.3. But apart from unofficial roms, that was it.

Fixing (some of) the issues

I finally installed a beta Icecream Sandwich (4.04) rom, but now the phone crashes a few times per day. Downgrading to 2.3 did not fix this crash. Generally, the crash isn’t problematic, but as my phone is my alarm clock, when it crashes overnight, I get to sleep-in.

I stayed with 4.04 as some apps, including the modern, greatly improved google keyboard, simply don’t support Gingerbread.

Also, it is laggy as heck.

Phone usage

  • I do use the phone/SMS functionality so that isn’t optional
  • Non-phone communication – I have Y! Mail, Gmail, LinkedIn, Viber installed
  • Internet browser
  • Alarm-clock – I have fairly specific requirements here and Alarm Clock Plus works really well for me
  • Evernote, Dropbox
  • TODO list (Wunderlist)
  • Music Player
  • Games

Why WP8 ?

I’d be happy to stick with Android, to be honest. But:

  • None of the current flagship android phones are particularly tempting, e.g. Galaxy S4, HTC One, Xperia Z …
  • It costs £100 for an unlocked smart phone (Lumia 520) !
  • It covers most of my use cases

Experience so far

  • So far it has been pretty snappy. The specs are not a million miles away from the Desire on paper (1GHz CPU, albeit dual core and more recent I guess, 512MB of memory), but even so, it’s a far nicer experience
  • I’m covered with most apps – Mail, LinkedIn, Shared (Google-linked) Calendar, RSS readers, Browser, …
  • I’m disappointed with the enhanced alarm apps. There is a limitation in WP8 which means that alarm apps can’t work correctly in the background and in any case, have limited access to the volume. I’d like to have an app that begins by vibrating and then have a sounds that slowly increases in volume. Maybe I could simulate this with an appropriate tune?

Perl “Not Generators”

Reading through the Generators page on the Python wiki inspired me to knock up something almost completely unlike generators using closures (something Perl has that Python hasn’t…) just for fun.

Edit: correction, thanks Bernhard.

Standard preamble…

use strict;
use warnings;

The count() not-generator

sub count
{
    my $cnt = -1;
    return sub {
        return ++$cnt;
    };
}

Helper function to make it easier to make not-generators

sub make_generator (&)
{
    my $sub = $_[0];
    my $finished = 0;
    return sub {
        return undef if $finished;
        local $_ = $sub->();
        $finished = 1 unless defined $_;
        return $_;
    };
}

Composing not-generators

sub compose (&$)
{
    my ($op, $generator) = @_;
    return sub {
        local $_ = $generator->();
        return undef unless defined $_;
        return $op->($_);
    };
}

Takewhile …

sub takewhile (&$)
{
    my ($match, $generator) = @_;
    return make_generator {
        local $_ = $generator->();
        return $match->($_) ? $_ : undef;
    };
}

Foreach not-generator

I have to implement my own looping of course.

sub generator_for (&$)
{
    my ($fn, $generator) = @_;
    while (defined(my $ret = $generator->())) {
        $fn->($ret);
    }
}

Whew. And finally, after all that I can do the squares thing.

my $squares = compose { $_ * $_ } count();
my $bounded_squares = takewhile { $_ < 100 } $squares;
generator_for { print @_, "\n" } $bounded_squares;

I finally got around to watching the Python keynote recommended by Steve. Two thirds of the “things we have that other people don’t have” is Python finally catching up with Perl features from 1995 and they were in other languages more than 10 years before that (is that ignorance or the Blub effect?). And we already have the rest in various libraries.

Oh well…

Stop me if you’ve heard this one:

A Perl programmer and a Python programmer walk into a bar.

Python dev says “why are you using Perl, Python is much clearer”

“What do you mean”, says Perl dev, “how is it clearer?”

“It’s obvious innit,” says Python dev. It’s cleaner and better It’s got, er, objects and stuff.

C/C++ integration aside, has anyone got anything more meaningful than “cleaner and better” ? I’m genuinely curious.

Parallel::Iterator

While looking at the Job Manager script from last week, I omitted the section where each job section of the batch returns the result to the manager.

The job serialises a hash containing the results to disk using Storable. When the jobs have all finished, the manager retrieves the data using the identifier.

my $results = {};
my $id = $manager->identifier();
foreach (>/tmp/*_$id.result<) {
    if (! m{^/tmp/(\d+)_}) {
        say "Error: unable to retrieve id from $_";
        next;
    }
    $results->{$1} = retrieve($_);
}

use Data::Dumper;
print Dumper($results);

Now it turns out, there is yet another handy cpan module called parallel::iterator, which can return the output of each job in an output list. (Under the covers, it has pipes between the processes and serialises the data between them using Storable).

And I was going to say, it would be nice if folks on Ironman talked about useful modules they came across from time to time.

Except they do already. dagolden already spoke about parallel::iterator here.

Wouldn’t it be handy if you could tag your ironman posts with a hashtag, like #cpanmodules and clicking on the hashtag would return the results?

Ironman: #cpanmodules #fork

The other day I was looking at a script that ran a bunch of more or less independent jobs in batches of four.

I’ve reproduced the core of the script as best as I can remember it.

Job

It has a class to represent the jobs themselves.

package Job;

use Moose;

has identifier => (
    is => 'ro',
    required => 1,
);

has cmd => (
    is => 'ro',
    required => 1,
);

no Moose;
__PACKAGE__->meta->make_immutable;

Job Manager

and a class that tries to ensure that 4 jobs are running in parallel wherever possible.

package JobManager;

use Moose;

use POSIX 'strftime';

has identifier => (
    is => 'ro',
    default => sub { strftime('%H%M%S', localtime(time())); },
);

has max_processes => (
    is => 'ro',
    default => 4,
);

has _job_id => (
    is => 'ro',
    writer => '_set_job_id',
    init_arg => undef,
    default => 1,
);

has queued_jobs => (
    is => 'ro',
    traits => ['Array'],
    isa => 'ArrayRef[Job]',
    default => sub { [] },
    handles => {
        enqueue_job => 'push',
        dequeue_job => 'shift',
        exist_queued_jobs => 'count',
    },
);

has running_jobs => (
    is => 'ro',
    traits => ['Hash'],
    isa => 'HashRef[Job]',
    default => sub { {} },
    handles => {
        add_running_job => 'set',
        delete_running_job => 'delete',
        num_jobs => 'count',
    },
);

sub next_job_id
{
    my $self = shift;
    my $job_id = $self->_job_id();
    $self->_set_job_id($job_id + 1);
    return sprintf "%02d", $job_id;
}

sub run_job
{
    my ($self, $job) = @_;

    my ($identifier, $cmd) = ($job->identifier(), $job->cmd());
    my $pid = fork();
    if (! defined($pid)) {
        say "Failed to run job $identifier";
    } elsif ($pid) {
        say "Running job $identifier ($pid)";
        $self->add_running_job($pid, $job);
    } else {
        system("$cmd > /tmp/$identifier.output 2>&1");
        exit;
    }
}

sub add_job
{
    my ($self, $name, $cmd) = @_;

    my $job = Job->new(
        identifier => (sprintf "%s_${name}_%s",
                               $self->next_job_id(), $self->identifier()),
        cmd => $cmd);

    if ($self->num_jobs() > $self->max_processes()) {
        $self->enqueue_job($job);
    } else {
        $self->run_job($job);
    }
}

sub main_loop
{
    my $self = shift;

    while (1) {
        my $pid = wait();
        last if ($pid < 0);
        say "Child $pid has exited";

        $self->delete_running_job($pid);
        while ($self->num_jobs() < $self->max_processes()) {
            last unless $self->exist_queued_jobs();
            $self->run_job($self->dequeue_job());
        }
    }
}

no Moose;
__PACKAGE__->meta->make_immutable;

Test Code

My test code to check if I got the code more or less correct.

my $manager = JobManager->new();

$manager->add_job('echo', 'sleep 10 ; echo hello');
for (1..9) {
    $manager->add_job('echo', 'sleep 2 ; echo hello');
}

$manager->main_loop();
jared@localhost $ ls -ltr /tmp/*echo*
-rw-r--r-- 1 jared jared 6 2011-07-03 19:32 /tmp/05_echo_193228.output
-rw-r--r-- 1 jared jared 6 2011-07-03 19:32 /tmp/04_echo_193228.output
-rw-r--r-- 1 jared jared 6 2011-07-03 19:32 /tmp/03_echo_193228.output
-rw-r--r-- 1 jared jared 6 2011-07-03 19:32 /tmp/02_echo_193228.output
-rw-r--r-- 1 jared jared 6 2011-07-03 19:32 /tmp/08_echo_193228.output
-rw-r--r-- 1 jared jared 6 2011-07-03 19:32 /tmp/07_echo_193228.output
-rw-r--r-- 1 jared jared 6 2011-07-03 19:32 /tmp/06_echo_193228.output
-rw-r--r-- 1 jared jared 6 2011-07-03 19:32 /tmp/10_echo_193228.output
-rw-r--r-- 1 jared jared 6 2011-07-03 19:32 /tmp/09_echo_193228.output
-rw-r--r-- 1 jared jared 6 2011-07-03 19:32 /tmp/01_echo_193228.output

Conclusion

I took two lessons away.


Parallel::Queue would have greatly simplified the core of this script. How many CPAN modules could my code benefit from equally if only I knew about them?


fork() is nice and easy to deal with. The code to manage the processes isn’t hugely complicated and seems pretty robust (careful, I may not have duplicated the robustness here).

Perl 6

The latest from chromatic (emphasis mine):

"If you think people don’t like Perl because the Perl 6 project started almost ten years ago, you haven’t been paying attention.

(Think Python has better marketing? Guido announced Python 3000 before Larry announced Perl 6, and it still took the better part of eight years for the Python developers to produce Python 3, and people are still upset that Python 3 is a wholesale replacement for Python 2, and there’s still a debate over when – and in some cases, if – major projects using Python will embrace Python 3 and abandon Python 2. Think about that.)"

Okay, I didn’t see any regret for shafting Perl 5 for the last 10 years, but great! I’m so happy that the opposition made the same stupid mistake that we did. </sarcasm>

Follow

Get every new post delivered to your Inbox.