Seitenanfang

Perl-Sünden

Dieser Post wurde aus meiner alten WordPress-Installation importiert. Sollte es Darstellungsprobleme, falsche Links oder fehlende Bilder geben, bitte einfach hier einen Kommentar hinterlassen. Danke.


Den heutigen Tag habe ich gefühlt nur mit Bugfixes verbracht. Keine komplizierten, schwer zu findenden Bugs, sondern kleine fiese dumme Minikäfer die einfach nur nervig sind.

[caption id="attachment_492" align="alignleft" width="150" caption="by Bruce Marlin"][/caption]

In einigen Sprachen müssen Variablen initialisiert werden, damit sie keinen unvorhersehbaren Wert haben. Perl gehört nicht dazu und das Verhalten einiger Entwickler kann zu echten Probleme führen. Aber der Reihe nach:

Auslöser waren Warnings von Zeilen wie Diesen:

my (%tableSum) = {};my %client_hash = {};my @attachments = [];
Es handelt sich hierbei um echte Fehler, denn der solchen Source schreibende Entwickler erwartet mit an Sicherheit grenzender Wahrscheinlichkeit danach ein leeres Hash oder Array vorzufinden, tatsächlich enthält das Hash aber einen Key mit undefined value bzw. das Array eine Array-Ref:
perl -MData::Dumper -le '%h = {}; @a = []; print Dumper \%h, \@a;'$VAR1 = {'HASH(0x1593df0)' => undef};$VAR2 = [[]];
Bei dem Hash-Key handelt es sich zudem nicht um eine Referenz, da Referenzen in Hash-Keys nicht zulässig sind und automatisch zu reinem Text konvertiert werden. Im weiteren Verlauf kommt es dann meist zu Folgefehlern (weil ein unerwarteter Hash-Key auftaucht und die scheinbare Referenz nicht auflösbar ist) oder unerwarteten Effekten, beispielsweise:
my @values = [];[...]push @values, 1, 2, 3;[...]$sth->execute(@values);

DBD::mysql::st execute failed: called with 4 bind variables when 3 are needed at /home/global_bo_planet49_com/cgi-bin//GLOBAL/DB.pm

Diese zu finden und zu eliminieren kann immens viel Zeit (und damit Geld) kosten.

Ebenfalls sehr beliebt:

my @provider = ();my %hashref_regs = ();my %hashref_list = ();
Diese leeren Zuweisungen sind wenigstens nicht falsch sondern einfach nur überflüssig - und ebnen den Weg für die o.g. Fehler.

Diese Syntax wird auch in der einschlägigen Dokumentation nicht erwähnt. Vielmehr steht dort:

The parameter list to my() may be assigned to if desired, which allows you to initialize your variables. (If no initializer is given for a particular variable, it is created with the undefined value.)

Perl Best Practices geht dagegen davon aus, dass häufig genutzt Strukturen vom Gehirn intuitiv als "richtig" und abweichende Syntax als "falsch" erkannt wird, eine Umgewöhnung ist trotzdem recht einfach und kurzfristig möglich.

Wer also regelmäßig %hash = () schreibt, wird auch %hash = {} oder %hash = [] als "richtig" empfinden, auch wenn bei näherer Betrachtung die unterschiedlichen Klammern (hoffentlich) auffallen, der Verzicht auf die non-Standard-Syntax "= ()" reduziert demnach auch die Fehler durch falsche Klammern.

Die Krönung fand sich dann aber in einem Modul:

my @attachments = [];
[...]
@attachments = [{ file => $tmp_filename }] ;
[...]
Mail_send(attachments => @attachments);
Die Chance, dass dieses zwar funktionierende aber bei der nächsten Änderung hochgefährliche Konstrukt Absicht war, dürfte gegen Null tendieren. Vermutlich hat die falsche Initialisierung zu leeren/falschen Attachments oder Fehlern bei der Prüfung durch die aufgerufene Funktion geführt und der Verursacher hat so lange rumprobiert bis es irgendwie funktioniert hat.

Datenvalidierung

Date::Calc reagiert ziemlich sensibel auf falsche Datumsangaben - obwohl sich diese meist sogar problemlos mathematisch rechnen lassen würden, also sollte jedes übergebene Datum vorher mit check_date (ebenfalls aus Date::Calc aber kein Sensibelchen) geprüft werden. Da aber grundsätzlich jeder Entwickler jeden einzelnen Parameter 100% sauber verifiziert, entsteht dieses Problem in der Praxis gar nicht...

Useless use

Jedes benutzte Modul sollte auch per "use" eingebunden werden... warum schreibe ich solche Selbstverständlichkeiten, die 1742 Fehlermeldungen meines Check-Scripts sind bestimmt alle "false Positives". Das Script gibt es vielleicht auch irgendwann in einem anderen Post.

CPU-Zeit und RAM sind unendliche Güter...

Bereits vor ein paar Tagen hatte ich folgende sub bereinigt:
sub str_to_time {  my ($date_string, $format) = @_;  my $date_string = shift;[...]  my $ret = {    items => \@items,    previos_page => $previos_page,    next_page => $next_page,    pages_count => $pages_count  };}
Die Variable $ret wird fleißig gefüllt - und dann nicht benutzt. Eine klare sinnlose Verschwendung von CPU-Zeit und RAM (wenn auch von Beidem nicht viel), oder?

Heute stellte sich heraus, dass der Autor damit eigentlich eine sehr komische - wenn auch logischerweise funktionierende - Version eines return erstellt hatte und sich in anderen Funktionen darauf verlassen hat.

 

1 Kommentar. Schreib was dazu

  1. Wenn es nicht so traurig wäre, könnte man ja fast schmunzeln... Leider passieren solche Fehler immer wieder. Einsteiger begehen sie und die "alten Hasen" übersehen es.


    Bei uns gibt es noch einen beliebten Fall:



    my $skalar = undef;
    my @array = undef;


    auch hier empfindet man nach gewisser Zeit die sinnlosen "undef" Initialisierungen irgendwann als normal und übersieht zu schnell den kleinen Unterschied zwischen Skalaren und Arrays. Leider.

Schreib was dazu

Die folgenden HTML-Tags sind erlaubt:<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>