Ein Teller Spaghetti sieht verworren und unübersichtlich aus. Von diesem Aussehen leitet sich der Name Spaghetticode ab. Spaghetticode ist ein abwertender Begriff für Software-Quellcode, der komplexe und verworrene Kontrollstrukturen aufweist.
sub block_example { my ($number, $count, $offset) = @_; $number *= $count; $number += $offset; return $number; }
Aufgabe: Dateien mit unterschiedlichem Encoding einlesen und die Werte darin sortiert als Tabelle in HTML ausgeben.
Die Aufgabe ist einfach
Morgen kommt jemand auf die Idee, dass die Ausgabe in Excel benötigt wird - oh.
use strict; use warnings; no warnings qw(uninitialized);
Alles andere sollte ohne Codezerstörung behebbar sein. Sinnvollerweise das "no warnings" nicht global, sondern nur in die fehlerhaften Blöcke einfügen. Beim weiteren Refactoring verschwinden diese dann wieder.
local $SIG{__DIE__} = sub { use Carp qw(confess); confess @_ }; local $SIG{__WARN__} = sub { use Carp qw(cluck); cluck @_ }; local *CORE::GLOBAL::die = sub { ...; die ...; }; local *CORE::GLOBAL::warn = sub { ...; warn ...; };
PackageName::__ANON__()
im caller stack
my $code_ref1 = sub { local *__ANON__= 'code_ref1'; ... }; my $code_ref2 = sub { local *__ANON__= 'code_ref2'; ... };
sigtrap - oder warum File::Temp bei "ctrl C" nicht aufräumt.
use sigtrap 'handler' => \&my_handler, 'normal-signals'; use sigtrap 'handler' => sub { exit }, 'normal-signals';
Moose::Util::TypeConstraints |-- Any `-- Item |-- Bool |-- Maybe[`a] |-- Undef `-- Defined -------. | \ `-- Value `-- Ref `-- Str |-- ScalarRef[`a] |-- Num |-- ArrayRef[`a] | `-- Int |-- HashRef[`a] |-- ClassName |-- CodeRef `-- RoleName |-- RegexpRef |-- GlobRef |-- FileHandle `-- Object
Defined `-- Value `-- Str `-- Num
Jetzt weiss ich, warum $var == 0 Warnungen werfen kann.
Hier hilft "use Scalar::Util qw(looks_like_number);".
Kontext: Es ist nicht nur entscheidend, was man schreibt, sondern auch in welchem Umfeld.
if ( scalar @errors > 0 ) { if ( @errors > 0 ) { if ( @errors ) {
http://perldoc.perl.org/perlop.html
perl -e 'use Devel::Peek; Dump 1 == 1'
und
perl -e 'use Devel::Peek; Dump 0 == 1'
Devel::Peek schaut in den Bauch einer Perl-Datenstruktur.
SV - Scalar value Flags IOK -> int gültig NOK -> numeric gültig POK -> pointer auf String gültig READONLY -> 0 == 1 = 1 geht eben nicht zu schreiben IV = 1 -> int ist 1 NV = 1 -> numeric ist 1 PV -> es liegt ein string auf Adresse 0x... mit dem Wert "1" mit \0 abgeschlossen CUR = 1 -> Der string hat eine Länge von 1 LEN = 1 -> Die gesamte Datenstruktur hat eine Länge von 8 Bytes
Für viele, die aus anderen Programmiersprachen kommen, ist schon mal völlig unklar, wie ein Scalar gleichzeitig mehrere gültige Werte (String, Numeric, Integer) beinhalten kann.
"https://metacpan.org/module/Scalar::MultiValue" ist ein Modul, mit dem man das aktiv machen kann.
|| && and or
macht das nicht. Hier wird der rechte Teil der Anweisung nicht boolsch evaluiert.
Deswegen ergibt
50 && 100
100 und nicht nur einen wahren Boolean.
Dual-Value numerisch verwenden
$boolean = !! $any; $numeric = 0 + $boolean; $string = q{} . $boolean; 0 + !! 'bla' 0 + !! ( $result && $result->event )
$array_ref = [1, 2]; # nein, das ist keine Listen Referenz $scalar_ref = \(1, 2); # nein, das ist auch keine Listen Referenz @scalar_refs = \(1, 2); scalar @array @array = ($scalar);
sub my_method { my (undef, $second) = @_; defined wantarray or return; # called in void context # hier evtl. aufwendige Ermittlung der Rückgabe return wantarray ? $second # called in list context : [ $second ]; # called in scalar context }
sub my_method { my (undef, $second) = @_; my @any; if ( defined wantarray ) { # hier evtl. aufwendige Ermittlung der Rückgabe if ( wantarray ) { @any = ( $second ); # called in list context } else { @any = ( [ $second ] ); # called in scalar context } } else { # called in void context @any = (); } return @any; }
@array = (1, 2, 3); %hash = (1, 2, 3); # Odd number of elements in hash assignment
() zum Leeren passt immer
$integer = () = "1\n2\n3\n" =~ m{ ( \n ) }xmsg; # 3
sub value { my @values = @_; return @values ? $value[0] : (); # () und nicht undef } my %hash = ( undef => scalar value(), empty => [ value() ], one => scalar value(1), );
my ${scalar} = 'string'; ${_}->sub();
Häufungen von schließenden Klammern sind Zeichen für schlechte Strukturierung. Bei den öffnenden Klammern stelle man ich z.B. if vor.
{{{{{{{{{{ ((((( 1 ))))); }}}}}}}}}}
{} als Block oder als Hash-Referenz ?
@array = map { 1; { $_ => $_ } } (1, 2); # block @array = map { 1; { $_ => $_ }; # block } (1, 2); @array_of_hash = map { 1; +{ $_ => $_ }; # hash reference } (1, 2);
() als gruppierende oder Funktionsklammer?
# Funktionsklammer return ( 5 - 2 ) * 3; # 3 # gruppierende Klammer return +( 5 - 2 ) * 3; # 9 # Leerzeichen nach + => unlesbar return + ( + ( + ( 5 ) - + ( 2 ) ) * 3 ); # 9