borewa: Variablen Referenz in Subs

Guten Tag,

Ich übergebe ein paar Referenzen von Variablen (Array, Scalar, Hash) an verschiedene Subs, die die überprüfen und auch veränderungen an den Variablen vornehmen.

Der Aufruf ist natürlich klar ...
&check_kunde(\@Array, \Scalar);

Nur muss ich ja innerhalb des Sub mit @$ oder $$ arbeiten um die Varibalen ansprechen zu können, was mir aber auf dauer etwas zu nervig ist, da ich größere Teile ins Sub auslagere und da nicht überall ein zusätzliches $ einfügen möchte.

sub check_kunde ($$) {  
$nummern = shift;  
  
$nummern_art = shift;  
my $elem;  
  
   foreach $elem (@$nummern) {  
      $$nummern_art = 1;  
   }  
}

Wenn ich dies hier mache, dann kann ich die Variablen ganz normal mit @ oder $ ansprechen.

sub check_kunde ($$) {  
$nummern = shift;  
@nummern = @$nummern;  
  
$nummern_art = shift;  
$nummern_art = $$nummern_arten;  
  
[...]  
}

Gibt es aber vielleicht eine kürzere version davon, weil jedes mal 2 Zeilen nur um die Variable etwas um zubiegen ist auch nervig, bzw. verringert etwas die übersicht.
Gibt es keine Abkürzung richtig:
@array = @shift;

  1. Ich übergebe ein paar Referenzen von Variablen (Array, Scalar, Hash) an verschiedene Subs, die die überprüfen und auch veränderungen an den Variablen vornehmen.

    Der Aufruf ist natürlich klar ...
    &check_kunde(\@Array, \Scalar);

    Die Schreibweise mit dem '&' ist schon einige Perl Generationen überflüssig und sollte auch vermieden werden.

    Nur muss ich ja innerhalb des Sub mit @$ oder $$ arbeiten um die Varibalen ansprechen zu können, ..

    Auch das ist schon lange nicht mehr so. Dereferenzieren kannst du auch mit der "Pfeil" schriebweise. Also $array->[index], wobei der Skalar nicht als Referenz übergeben werden muss.

    sub check_kunde ($$) {

    }

      
    prototypen sind zwar aktueller, aber nicht unbedingt beliebt. Ich benutze sie nie.  
      
    
    > Gibt es keine Abkürzung richtig:  
    > `@array = @shift;`{:.language-perl}  
      
    Wenn du eine Array Referenz übergibst kannst du diese natürlich auch in eine Array Variabel kopieren, das ist aber nicht unbedingt sinnvoll (Kopie von grossen Datenmengen). Besser ist dereferenzieren.  
      
    Struppi.
    
  2. sub some_sub {  # array_ref, hashref, stringref, string  
      my $array = @{ shift(@_) };  
      my %hash = %{ shift(@_) };  
      my $scalar1 = ${ shift(@_) };  
      my $scalar2 = shift;  
    }  
    
    

    mfg Beat

    --
    ><o(((°>           ><o(((°>
       <°)))o><                     ><o(((°>o
    Der Valigator leibt diese Fische
  3. Hallo C-Programmierer!

    Ich modernisiere zunächst deine Programmierpraktiken; Struppis Haltung zum ersten Thema ist mir nicht streng genug formuliert.

    ① Prototypes nicht mehr benutzen: http://stackoverflow.com/questions/297034 Perl::Critic verbietet dies auch.

    ② Argumente in einer Zeile entpacken: http://www.perl-community.de/bat/poard/thread/14780 Perl::Critic fördert dies auch.

    ③ Das direkte Verändern von Parametern ist sehr unperlig.
    • Nachteile:
        ‣ Du handelst dir Probleme mit versteckten Zustand und Nebenwirkungen ein,
        ‣ vernichtest zukünftige Möglichkeiten der Compileroptimierung (Stichpunkt Unveränderlichkeit) und
        ‣ erhöhst das Risiko der Eintrittsvarianz beträchtlich.
    • Vorteile: Keine.

    Perl war schon immer in der Lage, mehrere Werte zurückzuliefern, also tue das.

    ――――

    Bleibt das explizite dereferenzieren:

      
    sub check_kunde {  
        my ($nummern_aref, $nummern_art) = @_; # kein Aliasing mehr, siehe perldoc perlsub  
        [...]  
        @{ $nummern_aref } blah blah $nummern_aref->[blah blah]  
        [...]  
        return $nummern_aref, $nummern_art;  
    }  
    
    

    Mehr ist mit Bordmitteln derzeit nicht drin. Wenn du aber magst, kannst du zusätzliche Module wie MooseX::Declare benutzen, welche die Syntax aufmöbeln und dank Funktionssignaturen das Entpacken von @_ unnötig machen.

    1. ③ Das direkte Verändern von Parametern ist sehr unperlig.

      Das direke verändern ist in unzähligen Funktionen enthalten.
      chomp() mal nur als Beispiel.

      • Nachteile:
          ‣ Du handelst dir Probleme mit versteckten Zustand und Nebenwirkungen ein,
          ‣ vernichtest zukünftige Möglichkeiten der Compileroptimierung (Stichpunkt Unveränderlichkeit) und
          ‣ erhöhst das Risiko der Eintrittsvarianz beträchtlich.
      • Vorteile: Keine.

      Oh doch: Speicher. Aber das ist bald alles.

      Aber einen Nachteil hast du nicht aufgezählt:

      somefunc(\"literal");  
        
      sub somefunc{  
        my $scalarref = shift;  
        $$scalarref = "newvalue"; # ERROR  
        # oder auch  
        $$_[0] = "newvalue"; # ERROR  
      }  
      
      

      Tipp.

      Die Übergabe von Hashes oder Hashreferenzen erachte ich als auch bei prozeduraler Programmierung als Tugend, nicht nur in OOP.
      Sie machen ein Upgrade von Funktionen möglich, ohne dass man jede Funktionsverwendung upgraden muss.

      some_sub( {  
           scalarvar=>'scalar',  
           arrayvar=>[1,2,3],  
           hashvar=>{x=>1}  
        } );  
      
      

      mfg Beat

      --
      ><o(((°>           ><o(((°>
         <°)))o><                     ><o(((°>o
      Der Valigator leibt diese Fische
      1. Das direke verändern ist in unzähligen Funktionen enthalten.
        chomp() mal nur als Beispiel.

        Tja, was soll man sagen, es ist ein Designfehler, dass die Funktion nicht das modifizierte Argument zurückliefert. Das zeigt sich sehr deutlich beim Verketten. Beispielcode (mit autoboxing):

          
            [<DATA>]  
            ->grep(sub {$_[0] !~ /\A (?: [#] | \s* \z )/msx}) # skip empty lines, comments  
            ->map(sub {chomp $_[0]; return $_[0];}) # ← häääääääääässlich  
            ->join(q{ })  
            ->say  
        
        

        Glücklicherweise gibt es chomped.

        Mir ist bewusst, dass dieser Designfehler sich häufig bei dünn umhüllten C-Funktionen bemerkbar macht.

        [der geringere Verbrauch von] Speicher [ist ein Vorteil, weil Datenstrukturen nicht in der Gesamtheit kopiert werden]

        Zugestanden. Mir ist das entfallen, weil ich nicht auf den Speicherverbrauch schaue, wenn ich mit Perl programmiere, denn das ist Sparsamkeit am falschen Ende und wie jede vorzeitige Optimierung ein größes Übel. Im Notfall lagere ich die kritischen Teile an Inline::C ö.ä. aus.

        Aber einen Nachteil hast du nicht aufgezählt: [Modification of a read-only value attempted]

        Moment mal, das ist kein Merkmal, das durch Referenzen, sondern Aliasing entsteht!

          
            sub somefunc {  
                $_[0] = 'newvalue'; # funktioniert genauso schlecht.  
            }  
          
            somefunc('literal');  
        
        

        Wie bereits im letzten Beitrag angedeutet, soll man besser immer Kopien von @_ erzeugen statt Aliase.

        Die Übergabe von Hashes oder Hashreferenzen erachte ich als auch bei prozeduraler Programmierung als Tugend, nicht nur in OOP.

        Volle Zustimmung! Die Empfehlung lautet, Umstieg auf hashbasierte Parameter lohnt sich ab 3 Argumenten. Ich halte sie für falsch. Aus Erfahrung finde ich, man fährt *immer* mit hashbasierten Parametern am besten, auch wenn's nur einer ist. Es bringt Flexibilität für den Benutzer und Bequemlichkeit für den Programmierer von Anfang an.