manni: $_[0] problem

Hi!

kurz und knapp: Ich mache eine eingabe sie kommt in eine subroutine wird umgewandelt und wieder ausgegeben.

Zur verständlichkeit:
#!/usr/bin/perl
$a = <STDIN>;  #Eingabe ist "Hallo"
chomp $a;
print $a;   #logischerweise immernoch "Hallo"
umwandeln($a)   #Hier wird $a in die sub gegeben
sub umwandeln
{
  my $wandel = shift;
  $wandel = "Bye";
}
print $a;    # $a sollte jetzt "Bye" sein.

Warum klappt das nicht? Wenn ich die sub aber so mache:

sub umwandeln
{
  $_[0] = "Bye"
}

Geht es.

Ich bin wirklich kein freund von variablen namens $_ und würde echt gerne wissen warum das nicht geht?
my $wandel = shift;
ist doch das ganz selbe wie
$_[0] oder versteh ich da etwas falsch?

Kann es sein das es nicht geht weil ich nur ein parameter übergebe ich aber eine liste damit aufrufe?
Bitte um hilfe.

  1. Hi!

    Entschuldigt bitte meinen doppelpost ich kann aber nicht editieren.
    Beim durchlesen ist mir aufgefallen das ich gar nicht gesagt habe was genau nicht klappt.

    Nachdem $a in der sub umgewandelt ist sollte er auch im ganzen hauptprogramm ansprechbar sein

    print $a;   # logischerweise immer noch Hallo
    sub umwandeln
    {
      my $wandel = shift;
      $wandel = "Bye";
    }
    print $a; # sollte jetzt auch ausserhalb der sub "Bye" heissen. Das geht aber nur wenn ich mit $_[0] den Text ändere.

    Hoffe es ist klar?

    1. Moin!

      Hoffe es ist klar?

      Ja. Du musst mal nachlesen, wie in Perl Funktionen Werte übergeben werden, wie Perl aus Funktion Werte zurückgibt, was mit den in Funktionen verwendeten Variablen nach Beendigung der Funktionen passiert und was eine locale oder globale Variable (Bleistift: dieses $_) überhaupt ist...

      MFFG (Mit freundlich- friedfertigem Grinsen)

      fastix®

      --
      Als Freiberufler bin ich immer auf der Suche nach Aufträgen: Schulungen, Seminare, Training, Development
      1. Ja. Du musst mal nachlesen, wie in Perl Funktionen Werte übergeben werden, wie Perl aus Funktion Werte zurückgibt, was mit den in Funktionen verwendeten Variablen nach Beendigung der Funktionen passiert und was eine locale oder globale Variable (Bleistift: dieses $_) überhaupt ist...

        Lieber fastix!
        Ich würde hier nicht fragen wenn ich es nicht wüsste.
        Hier mal ein !!!PAAR!!! webseiten die ich danach durchsucht habe - das ist nicht mal im entferntesten 1/4 davon wieviele ich gelesen habe.

        http://de.selfhtml.org/perl/sprache/subroutinen.htm
        http://www.comp.leeds.ac.uk/Perl/subroutines.html
        http://faq.perl-community.de/bin/view/Perldoc/perlsub
        http://stein.cshl.org/genome_informatics/subroutines/
        http://www.privatrecht.sbg.ac.at/perl-tutorial/perl/perl_ref.html
        http://books.google.de/books?id=zkX0RNHxTM0C&pg=PA62&lpg=PA62&dq=r%C3%BCckgabe+perl+subroutine&source=web&ots=8bmBwqCA2F&sig=RQI7Jj6-gbygDZbF9iLaW8DHkBE&hl=de&sa=X&oi=book_result&resnum=9&ct=result
        http://www1.uni-hamburg.de/wwwtrost/PerlCGI/perlsubr.html
        http://www.perl.com/pub/a/2006/02/23/advanced_subroutines.html
        http://www3.futureware.at/artikel/perlkurs.htm
        http://www.oreilly.de/catalog/einperl3ger/chapter/f_Kap04.html
        http://www.cs.rpi.edu/~hollingd/eiw-2003/notes/PerlSubs/PerlSubs.html
        Darüber hinaus habe ich auch meine Bücher die ich daheim liegen habe danach abgesucht.

        Und ich weiss was damit passiert und es macht auch keinen unterschied ob ich my oder local oder our benutze. Auch ist mir sehrwohl bewusst was $_ (die im übrigen nichts mit $_[0] zu tun hat) bedeuten sollte.

        Danke dennoch.

        1. Moin!

          Ja. Du musst mal nachlesen, wie in Perl Funktionen Werte übergeben werden, wie Perl aus Funktion Werte zurückgibt, was mit den in Funktionen verwendeten Variablen nach Beendigung der Funktionen passiert und was eine locale oder globale Variable (Bleistift: dieses $_) überhaupt ist...

          Lieber fastix!

          Dann lies auch die dortigen Beispiele, die Antwort von Beat und die meinige weiter oben...

          Danke dennoch.

          Bitte.

          MFFG (Mit freundlich- friedfertigem Grinsen)

          fastix®

          --
          Als Freiberufler bin ich immer auf der Suche nach Aufträgen: Schulungen, Seminare, Training, Development
  2. Kann es sein das es nicht geht weil ich nur ein parameter übergebe ich aber eine liste damit aufrufe?
    Bitte um hilfe.

    Wenn die eine funktion mit Parameter aufrufst, dann werden die Werte in @_ kopiert.
    mit shift holst du dir das erste Element aus @_.

    Wenn du statt der Kopie einer Variable die echte Variable übergeben willst, musst du Referenzen übergeben.

    my $x = 1;
    myadd($a);
    print $a; # Ausgabe 2

    sub myadd{
      my $scalarref = shift;
      $$scalarref += 1; # hier dereferenzieren
    }

    PS verwende use strict.

    mfg Beat;

    --
    Woran ich arbeite:
    X-Torah
    ><o(((°>           ><o(((°>
       <°)))o><                     ><o(((°>o
    1. Nur als hinweis, nicht dass du noch durcheinander kommst.

      my $x = 1;
      sollte
      my $a = 1;
      heissen.

      1. Nur als hinweis, nicht dass du noch durcheinander kommst.
        my $x = 1;
        sollte
        my $a = 1;
        heissen.

        Oder doch besser andersrum.

        my $x = 1;
        my $x = 1;
        myadd($x);
        print $x; # Ausgabe 2

        sub myadd{
          my $scalarref = shift;
          $$scalarref += 1; # hier dereferenzieren
        }
        [/code]

        Grund: $a und $b sind in Perl spezielle Variablen.
           sort{ sa <=> $b } @array
        Ich habe es nicht getestet, aber unter Umständen könnte die Verwendung von $a und $b unangenehme Nebenfolgen haben.

        mfg Beat;

        <o(((°>           ><o(((°>

        <°)))o><                     ><o(((°>o

    2. Wenn du statt der Kopie einer Variable die echte Variable übergeben willst, musst du Referenzen übergeben.

      Das ist ja alles richtig, aber ich muss gesetehn, ich weiß auf die eigentliche Frage auch keine Antwort und habe sei hier auch noch nicht gelesen.

      Warum ist der Zugriff auf $_[0] ein Zugriff auf die Referenz?
      Meine Vorstellung ist, dass es das erste Element von @_ ist und in dem Array @_ ist eine Kopie der Parameter. Mit dieser Erklärung ergibt das keinen Sinn:

      use strict;  
      my $a = 'Hallo';  
        
      print $a;  
      umwandeln($a);  
      print $a;  
        
      sub umwandeln {  
       $_[0] = 'bye';  
      }
      

      Also, wer weiß die Antwort?

      Struppi.

      1. Das ist ja alles richtig, aber ich muss gesetehn, ich weiß auf die eigentliche Frage auch keine Antwort und habe sei hier auch noch nicht gelesen.

        Warum ist der Zugriff auf $_[0] ein Zugriff auf die Referenz?
        Meine Vorstellung ist, dass es das erste Element von @_ ist und in dem Array @_ ist eine Kopie der Parameter. Mit dieser Erklärung ergibt das keinen Sinn:

        use strict;

        my $a = 'Hallo';

        print $a;
        umwandeln($a);
        print $a;

        sub umwandeln {
        $_[0] = 'bye';
        }

        
        >   
        > Also, wer weiß die Antwort?  
          
        Ich habe auch keine Standard-Antwort.  
        Ich frage mich, ob @\_ eine Liste von echten Referenzen darstellt, oder ob man den Mechanismus als Alias, also als Sonderfall interner Referenzen auffassen soll.  
        Das Verhalten ist:  
          
           myfunc($x,$y,$z)  
          
        bewirkt, dass @\_ eine Liste von Aliasen ist zu den Werten $x, $y, $z.  
        Durch manipulieren dieser Aliase manipuliere ich (analog zu $\_ in einer Schleife), den Wert direkt. Es handelt sich um einen Alias, also nicht um eine Kopie oder eine Referenz.  
        Aber:  
          
           myfunc('constant');  
          
        ergibt einen Error, wenn man versucht, $\_[0] zu modifizieren. Das bedeutet nicht dass ich die Elemente in @\_ nicht modifizieren darf, sondern dass die modifizierten Elemente immer auf eine Variable zeigen müssen, statt auf eine Konstante (Ja hier handelt es sich um Referenzen interner Art).  
        @\_ und $\_ (der Schleifen-Alias) verhalten sich diesbezüglich gleich.  
          
        Ich versuche es so zu unterscheiden:  
        Ein Alias ist eine implizite Referenz, das heisst es wird keine De/Referenzierung explizit verlangt. De/Referenzierung erfolgt bei jeder Art der Zuweisung oder Verarbeitung.  
        Aliase können nur dann manipuliert werden, wenn sie auf echte Variablen verweisen (hierin besteht ihre Natur als Referenz).  
          
        Beispiel:  
            $some\_var =~ /(.)/ and myfunc($1);  
        Manipulation von $\_[0] wäre eine irrtümliche Manipulation von $1.  
          
        Nun zur Frage des OP, warum geht folgendes nicht:  
           sub myfunc{  
             my $temp = shift; # das ist kurz für: shift @\_  
           }  
        shift @array entfernt das erste Element und kopiert den Wert in die neue Variable. That's it. Jeder Bezug geht verloren, sofern der Wert nicht eine Referenz war.  
          
        mfg Beat
        
        -- 
        Woran ich arbeite:  
        [link:http://www.elcappuccino.ch/cgi/tok.pl?extern=1-pub-com3306-1@title=X-  
           <°)))o><                     ><o(((°>o  
        
        
        1. [...]
          Nun zur Frage des OP, warum geht folgendes nicht:
             sub myfunc{
               my $temp = shift; # das ist kurz für: shift @_
             }
          shift @array entfernt das erste Element und kopiert den Wert in die neue Variable. That's it. Jeder Bezug geht verloren, sofern der Wert nicht eine Referenz war.
          [...]

          Nur der Vollständigkeit halber sollte man sagen, dass mit etwas Magie auch das Verhalten, welches sich der OP gewünscht hatte, erreicht werden kann: Statt

          my $temp = $_[0];

          oder ähnlichem schreibe man einfach

          local *temp = \$_[0];

          Dieser Code weist dem Skalarteil des Typeglobs *temp einen Alias auf das erste Arrayelement von @_ zu. Danach wirkt sich jede Modifikation an $temp auch auf den ursprünglichen Parameter aus.

          Natürlich ist dann $temp keine lexikalische Variable mehr. Wenn man das haben möchte, kann man theoretisch zu use PAD::Walker greifen, was dann aber wohl schon unter schwarze Magie fällt ;-)

          Generell würde ich von derartigem Code abraten. Die Lesbarkeit eines Programmes wird dadurch meistens nicht verbessert...

      2. Hallo!

        Warum ist der Zugriff auf $_[0] ein Zugriff auf die Referenz?

        AFAIK handelt es sich dabei um eine Notlösung aus grauer Urzeit, als es in Perl noch keine "echten" Referenzen gab.

        Aus "perldoc perlsub":
        ----------------------------------------------------
        Passing Symbol Table Entries (typeglobs)

        The mechanism described in this section was originally the only way to simulate pass-by-reference in older versions of Perl.
        [...]
        Scalars are already passed by reference, so you can modify scalar arguments without using this mechanism by referring explicitly to $_[0] etc.
        ----------------------------------------------------

        Grüße, Skrilax

      3. Warum ist der Zugriff auf $_[0] ein Zugriff auf die Referenz?

        Weil's in perlsub so steht:
        "Scalars are already passed by reference, so you can modify scalar arguments without using this mechanism by referring explicitly to $_[0] etc."

        Meine Vorstellung ist, dass es das erste Element von @_ ist und in dem Array @_ ist eine Kopie der Parameter.

        Genauso ist es. $_[0] ist das erste Element von @_. Manipuliert man $_[0], dann wirkt das auf die globale Variable @_, dies wiederum wirkt direkt auf die referenzierten Parameter. Das ist offenbar ein Relikt aus alten Zeiten, wie Skrilax schon schrieb, von dem man m.E. die Finger lassen sollte.

        Siechfred

  3. Moin!

    Hi!

    kurz und knapp: Ich mache eine eingabe sie kommt in eine subroutine wird umgewandelt und wieder ausgeben:

    Variante 1 mit Return

    #!/usr/bin/perl  
      
    $a = "Hallo";  
      
    sub gibText;  
    {  
      
      return "ollaH";  
    }  
      
    $a=gibText($a);  
    print $a . "\n";
    

    Variante 2 mit Referenzen

    #!/usr/bin/perl  
    $a = "Hallo";  
      
    sub gibText  
    {  
      $$a="ollaH";  
    }  
      
    $a=gibText(\$a);  
    print $a . "\n";
    

    MFFG (Mit freundlich- friedfertigem Grinsen)

    fastix®

    --
    Als Freiberufler bin ich immer auf der Suche nach Aufträgen: Schulungen, Seminare, Training, Development
  4. Hallo manni!

    sub umwandeln
    {
      my $wandel = shift;
      $wandel = "Bye";
    }

    $wandel ist eine neue Variable (eine Kopie) mit als Wert den Wert des ersten Elements von @_.

    sub umwandeln
    {
      $_[0] = "Bye"
    }

    Hier _ist_ $_[0] das erste Element von @_ (dessen Inhalt nur aus einem Element besteht, nämlich $a), weswegen durch die neue Zuweisung dieses Element einen neuen Wert erhält und

    print $a;

    nun "Bye" ausgibt.

    Oder sehe ich das falsch (4 Monate nicht geperlt...)?

    Wie schon im Thread vermerkt, sollten $a und $b für Vergleiche, Sortierungen  reserviert bleiben. Nimm andere Variablennamen für solche Beispiele.

    Viele Grüße aus Frankfurt/Main,
    Patrick

    --
    _ - jenseits vom delirium - _

       Diblom   [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
    Achtung Agentur! | Nichts ist unmöglich? Doch! | Heute schon gegökt?
    1. Hier _ist_ $_[0] das erste Element von @_ (dessen Inhalt nur aus einem Element besteht, nämlich $a), weswegen durch die neue Zuweisung dieses Element einen neuen Wert erhält und

      print $a;

      nun "Bye" ausgibt.

      Oder sehe ich das falsch (4 Monate nicht geperlt...)?

      Ja, siehst su.

      Wenn das ein normales Verhalten wäre dann ginge:

      my $x = 'hallo';  
      my @array = ($x);  
      $arry[0] = 'bye';  
      print $x; # -> hallo nicht bye  
      
      

      Struppi.

      1. Hallo Struppi!

        Oder sehe ich das falsch (4 Monate nicht geperlt...)?
        Ja, siehst su.

        Ich sehe, dass ich am Ball bleiben sollte, was ich momentan zeitlich nicht kann :(

        Danke!

        Viele Grüße aus Frankfurt/Main,
        Patrick

        --
        _ - jenseits vom delirium - _

           Diblom   [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
        Achtung Agentur! | Nichts ist unmöglich? Doch! | Heute schon gegökt?
      2. Hallo Struppi!

        Wenn das ein normales Verhalten wäre dann ginge:

        my $x = 'hallo';

        my @array = ($x);
        $array[0] = 'bye';
        print $x; # -> hallo nicht bye

          
        Wenn man das OP-Beispiel wie hier etwas ändert, und $x in einem Array packt:  
          
        ~~~perl
        my $x = <STDIN>;  #Eingabe ist "Hallo"  
        chomp $x;  
        print $x;   #logischerweise immernoch "Hallo"  
        my @arr = ($x);  
        umwandeln(@arr);   #Hier wird $a in die sub gegeben  
        sub umwandeln  
        {  
          $_[0] = "Bye"  
        }  
        print $x;    # Hallo
        

        wird nichts modifiziert.

        Viele Grüße aus Frankfurt/Main,
        Patrick

        --
        _ - jenseits vom delirium - _

           Diblom   [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
        Achtung Agentur! | Nichts ist unmöglich? Doch! | Heute schon gegökt?
        1. Wenn man das OP-Beispiel wie hier etwas ändert, und $x in einem Array packt:
          wird nichts modifiziert.

          logisch, die sub ändert den Wert von $arr[0], nicht von $x.

          Struppi.

  5. Ich versuche mal, das alles ein bisschen zusammenzufassen.

    kurz und knapp: Ich mache eine eingabe sie kommt in eine subroutine wird umgewandelt und wieder ausgegeben.

    Nein, sie wird eben nicht umgewandelt. Ich kommentiere mal Deinen Code häppchenweise:

    #!/usr/bin/perl  
    $a = <STDIN>;  #Eingabe ist "Hallo"  
    chomp $a;  
    print $a;
    

    Hier legst Du eine Packagevariable an. Sie ist global und überall im Script ansprechbar. Übrigens, $a ist eine vordefinierte Perl-Variable, von der Du die Finger lassen solltest.

    sub umwandeln  
    {  
      my $wandel = shift;  
      $wandel = "Bye";  
    }
    

    Hier legst Du eine lexikalische Variable an. Sie gilt ausschließlich im umgebenden Block, hier in der Sub "umwandeln". Ist der Block beendet, ist $wandel nicht mehr gültig, sämtliche Manipulationen sind vergessen.

    print $a;

    Das gibt logischerweise "Hallo" aus.

    Warum klappt das nicht? Wenn ich die sub aber so mache:
    [...]
    Geht es.

    Das wurde denke ich ausreichend erläutert.

    my $wandel = shift;
    ist doch das ganz selbe wie
    $_[0] oder versteh ich da etwas falsch?

    In der Tat. Du kopierst die in der globalen Variablen $_[0] enthaltene Referenz in eine private Variable. Damit wirken alle Manipulationen an dieser privaten Variable nur im umgebenden Block, aber nicht außerhalb. Und deshalb bleibt der Inhalt von $a "Hallo". Man sollte es vermeiden, die zwei Variablensätze von Perl miteinander zu vermischen, es sei denn, man weiß wirklich, was man tut. Vielleicht hilft Dir zum Verständnis der Artikel Coping with Scoping weiter.

    Du kommst auf mehreren Wegen aus dem Dilemma heraus. Entweder Du verwendest konsequent Packagevariablen (m.E. nicht mehr zeitgemäß):

    $x = 'Hallo';  
    umwandeln();  
    print $x;  
      
    sub umwandeln {  
      $x = 'Bye';  
    }
    

    Oder Du verwendest konsequent lexikalische Variablen:

    my $x = 'Hallo';  
    umwandeln();  
    print $x;  
      
    sub umwandeln {  
      $x = 'Bye';  
    }
    

    Oder so (m.E. der richtige Weg):

    my $x = 'Hallo';  
    $x = umwandeln($x);  
    print $x;  
      
    sub umwandeln {  
      my $arg = shift;  
      $arg = 'Bye';  
      return $arg;  
    }
    

    Der Code ist zwar ziemlicher Unsinn, hilft Dir aber möglicherweise, das Problem zu erkennen.

    Siechfred