La magie du perl ?

Pour mon employeur actuel, je suis amené à écrire pas mal de code en Perl. C'est un langage que j'apprécie moyennement, notamment pour la raison suivante.

Il y a quelques jours, j'ai cherché comment stocker une référence sur une méthode de classe. Technique relativement commune, j'ai d'abord écrit quelque chose dans ce goût là:

#!/usr/bin/perl -w

package test;

sub new { return bless {}; }

sub hello {
  my $self = shift;

  print "Hello $self\n";
}

package main;

$t = test->new();
$ref = \$t->hello;

$ref->();

Dans le cadre d'une méthode, ce code est incorrect. Au lieu de stocker une référence, la méthode est d'abord exécutée et c'est son éventuel résultat qui sera stocké.

Après quelques recherches sur la toile, je découvre qu'il existe plusieurs solutions (utilisation de la classe de base UNIVERSAL ou encapsulation de la méthode dans une closure).

La correction du code précédent peut donc se faire :

# comme ceci
$ref = $t->can("hello");
# ou comme cela
$ref = sub { $t->hello(@_) };

Je vous laisse choisir laquelle est la plus belle ;-)

Il subsiste néanmoins un léger problème. En général, on ne stocke pas une référence sur une méthode (au lieu d'une fonction) juste pour faire joli. Pour ma part, je le fais lorsque je sais avoir besoin d'accéder à d'autres informations comme les attributs d'une classe.

Si je modifie ma classe test comme suit :

package test;

sub new { return bless {text => "world"}; }

sub hello {
  my $self = shift;

  print "Hello $self->{text}\n";
}

le code précédemment corrigé redevient invalide! Son exécution doit normalement donner le résultat suivant :

Use of uninitialized value in concatenation (.) or string at ...
Hello

Mais que se passe-t-il? (hmmmm mais qu'est ce qu'il se passe?!)

Pour une raison que j'ignore encore, Perl ne passe pas l'instance de classe en tant que premier argument de la méthode comme il le fait d'habitude! Pour corriger ce problème, il suffit de passer manuellement l'instance de la classe en tant que premier argument à chaque utilisation de notre référence :

$ref->($ref);

Ce qui nous donnera enfin le résultat tant attendu :

Hello world

Bref, tout ça pour ça comme dirait l'autre...

0 commentaires

Aucun commentaire!

Postez votre commentaire