steckl: Unterschied zwischen "require strict" und "use strict"

Hi,

ich habe fogendes vereinfachtes Perlscript:

  
#!/usr/local/bin/perl  
  
# use strict;    # fuehrt zu Abbruch  
require strict;  # kein Abbruch  
  
print $abc;  
print "\naus\n";  

Wenn ich jetzt strict mit use einbinde wird abgebrochen, wenn ich es stattdessen mit require einbinde laeuft das Script bis zum Ende durch.

Kann mir jemand erklaeren, wo hier der Unterschied zwischen require und use liegt?

mfG,
steckl

  1. Wenn ich jetzt strict mit use einbinde wird abgebrochen, wenn ich es stattdessen mit require einbinde laeuft das Script bis zum Ende durch.

    require wird erst zur Laufzeit ausgeführt, d.h. es wird nicht die import Funktion augerufen und es findet keine Prüfung statt ob du die Variabeln deklariert hast. Warum das Skript im anderen Fall abgebrochen wird ist dir aber klar?

    Struppi.

    1. Hi,

      require wird erst zur Laufzeit ausgeführt, d.h. es wird nicht die import Funktion augerufen und es findet keine Prüfung statt ob du die Variabeln deklariert hast.

      Danke, dann ist das schonmal klar.

      Warum das Skript im anderen Fall abgebrochen wird ist dir aber klar?

      Ja, weil die Variable $abc nie deklariert, definiert oder initialisiert (eines der 3 wird den Fehle erzeugen;) wurde.

      Jetzt ist mir aber nochmal was aufgefallen:
      Wenn ich ein selbstgeschriebenes Modul einbinde und dort dann wieder auf eine unbekannte Variable zugreifen will wird nur abgebrochen, wenn in dem Modul "use strict" steht, nicht aber, wenn "use strict" nur im Script, das das Modul einbindet, steht.

      Beispiel:
      testScript.pl:

      #!/usr/bin/perl -w  
      use strict;  
      use tmp;     # gleiches Verhalten bei use und require  
      
      

      tmp.pm:

      #use strict;  
      package tmp;  
      sub testSub  
      {  
          print "test: $abc";  
      }  
      1;  
      
      

      Es wird nur abgebrochen, wenn ich in tmp.pm das use strict einkommentiere. Ich haette eigentlich erwartet, dass das use strict aus testScript.pl ausreicht.
      Ich war der Meinung, dass use sowas wie in C eine Praeprozessoranweisung ist, die den Code dann direkt einsetzt, bevor der Compiler (heisst das in Perl auch so?) den Code weiterverarbeitet.
      Da habe ich mich wohl geirrt?

      mfG,
      steckl

  2. Wenn ich jetzt strict mit use einbinde wird abgebrochen, wenn ich es stattdessen mit require einbinde laeuft das Script bis zum Ende durch. Kann mir jemand erklaeren, wo hier der Unterschied zwischen require und use liegt?

    Eine use-Anweisung wirkt wie folgt:

    BEGIN {  
      require Module;  
      import Module LIST;  
    }
    

    Dagegen wird require zur Laufzeit ausgeführt. Bei Modulen ist das meistens kein Problem, wohl aber bei Pragmas wie strict, da diese direkt Einfluss auf das Verhalten des Compilers nehmen (siehe perlvar $^H). Und nichts anderes tut strict.pm: Es manipuliert in Abhängigkeit seines Aufrufs Compiler-Optionen, nicht mehr.

    Dies funktioniert aber logischerweise nur innerhalb von BEGIN-Blöcken, nicht aber während der eigentlichen Kompilierung des Scriptes. Man muss sich das wie ein Kommandozeilenparameter vorstellen, den kannst du auch nur bei Programmaufruf mitgeben, wenn das Programm einmal läuft, dann mit den festgelegten Optionen.

    Siechfred

    --
    Ein Selbständiger ist jemand, der bereit ist, 16 Stunden am Tag zu arbeiten, nur um nicht 8 Stunden für einen Anderen arbeiten zu müssen.
    1. Aua, da bin ich alter Esel aber meilenweit am Kern vorbeigeschossen. Es ist zwar alles soweit richtig, aber das Problem ist in der Tat der nicht erfolgte Aufruf von import bei require. Und kein import bedeutet keine Manipulation von $^H.

      Nix für ungut :)

      Siechfred

      --
      Ein Selbständiger ist jemand, der bereit ist, 16 Stunden am Tag zu arbeiten, nur um nicht 8 Stunden für einen Anderen arbeiten zu müssen.
      1. Nix für ungut :)

        Zu früh entschuldigt, denn ich hatte doch Recht - irgendwie :)

        @steckl

        Ja, use funktioniert ähnlich wie eine Präprozessoreinstellung, weil es wie ein BEGIN-Block so früh wie möglich, also noch während der *Kompilierung* ausgeführt wird, sodass der automagische Aufruf von import und die damit im strict-Pragma verbundene Manipulation des Kompilerverhaltens *ab diesem Zeitpunkt* wirkt.

        Eine "require"-Anweisung wird zur Laufzeit ausgeführt, da könnte man ja auf die Idee kommen, das fehlende import einfach dranzuhängen. Das geht auch ohne Probleme, aber die Kompilierung ist zur Laufzeit Geschichte, sodass sich jede Änderung am Kompilerverhalten im Nichts auflöst.

        Nebenbei: import ist eigentlich nur eine Konvention, denn entweder ein Modul hat eine import-Funktion oder es hat keine. In strict.pm ist eine explizit definiert, allerdings kann jedes Modul eine Standard-import-Funktion vom Exporter-Package erben.

        Siechfred

        --
        Ein Selbständiger ist jemand, der bereit ist, 16 Stunden am Tag zu arbeiten, nur um nicht 8 Stunden für einen Anderen arbeiten zu müssen.
        1. Hi,

          Nix für ungut :)
          Zu früh entschuldigt, denn ich hatte doch Recht - irgendwie :)

          Hab ich mir auch gedacht. Mit deiner Entschuldigung hast mich nochmal verwirrt, als ich gerade dein vorheriges Posting verstanden hatte. Aber ich denke so weit ist es jetzt schonmal klar.

          @steckl

          Ja, use funktioniert ähnlich wie eine Präprozessoreinstellung, weil es wie ein BEGIN-Block so früh wie möglich, also noch während der *Kompilierung* ausgeführt wird, sodass der automagische Aufruf von import und die damit im strict-Pragma verbundene Manipulation des Kompilerverhaltens *ab diesem Zeitpunkt* wirkt.

          Was ich jetzt noch nicht verstehe ist, wenn ich schreibe "BEGIN { print 'test' }" wird das gleich ganz am Anfang ausgefuehrt, egal wo ob es am Anfang oder Ende des Scripts steht - was ja noch klar ist - aber wenn ich "use strict" am Ende des Programms schreibe hat es keine Wirkung auf den vorherigen Quellcode. Das wiederspricht irgendwie deiner Aussage.

          ...der automagische Aufruf ...

          Hat das was mit den hier so oft erwaehnten Glaskugeln zu tun? ;)

          mfG,
          steckl

          1. Was ich jetzt noch nicht verstehe ist, wenn ich schreibe "BEGIN { print 'test' }" wird das gleich ganz am Anfang ausgefuehrt, egal wo ob es am Anfang oder Ende des Scripts steht - was ja noch klar ist - aber wenn ich "use strict" am Ende des Programms schreibe hat es keine Wirkung auf den vorherigen Quellcode. Das wiederspricht irgendwie deiner Aussage.

            Das stimmt nicht, use strict kannst du hinschreiben wo du möchtest. use wird immer vor dem eigentlichen kompilieren ausgeführt.

            Struppi.

            1. Hi,

              Was ich jetzt noch nicht verstehe ist, wenn ich schreibe "BEGIN { print 'test' }" wird das gleich ganz am Anfang ausgefuehrt, egal wo ob es am Anfang oder Ende des Scripts steht - was ja noch klar ist - aber wenn ich "use strict" am Ende des Programms schreibe hat es keine Wirkung auf den vorherigen Quellcode. Das wiederspricht irgendwie deiner Aussage.

              Das stimmt nicht, use strict kannst du hinschreiben wo du möchtest. use wird immer vor dem eigentlichen kompilieren ausgeführt.

              Ich glaube du hast mich falsch verstanden. Was ich meinte ist, dass

                
              print "test $dsafdsaf";  
              use strict;  
              
              

              nicht das gleiche ist wie

                
              use strict;  
              print "test $dsafdsaf";
              

              Eigentlich sollte doch dann das use strict dem Kompiler sagen, dass er das Programm strenger behandeln soll, bevor es ausgeführt wird?

              mfG,
              steckl

              1. Eigentlich sollte doch dann das use strict dem Kompiler sagen, dass er das Programm strenger behandeln soll, bevor es ausgeführt wird?

                Ja, aber erst ab dem Punkt, wo es notiert wurde. Damit wäre use strict am Ende eines Scriptes wirkungslos.

                Siechfred

                --
                Ein Selbständiger ist jemand, der bereit ist, 16 Stunden am Tag zu arbeiten, nur um nicht 8 Stunden für einen Anderen arbeiten zu müssen.
            2. Hallo Struppi!

              Das stimmt nicht, use strict kannst du hinschreiben wo du möchtest. use wird immer vor dem eigentlichen kompilieren ausgeführt.

              Da bin ich nicht so sicher. Warum gibt es dann:

              no strict vars;
              ...Anweisungen...
              no strict refs;
              ...Anweisungen...
              no strict subs;
              ...Anweisungen...

              Wieder »strikt behandelt« wird, wenn irgendwann danach im Script notiert wird:

              use strict;
              ^ ab dann alles wieder »strict«.

              P.S.: Struppi, Du hattest letztes mal geschrieben, Du weißt nicht, was »use vars qw($foo, $bar, $blubb);« macht. Ich hatte darauf geantwortet, dann warst Du ein paar Tage nicht im Forum. Falls es Du es also noch nicht gelesen hast und es Dich noch interessiert:

              http://forum.de.selfhtml.org/archiv/2007/7/t157087/#m1021940

              Viele Grüße aus Frankfurt/Main,
              Patrick

              --

              _ - jenseits vom delirium - _
              [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
              Nichts ist unmöglich? Doch!
              Heute schon gegökt?
          2. Was ich jetzt noch nicht verstehe ist, wenn ich schreibe "BEGIN { print 'test' }" wird das gleich ganz am Anfang ausgefuehrt, egal wo ob es am Anfang oder Ende des Scripts steht - was ja noch klar ist - aber wenn ich "use strict" am Ende des Programms schreibe hat es keine Wirkung auf den vorherigen Quellcode. Das wiederspricht irgendwie deiner Aussage.

            Ja, BEGIN ist insofern verwirrend als Name. Die von strict provozierten Fehler werden während der *Kompilierung* gezogen, nicht zur Laufzeit. Letztlich weist "use strict" im chronologischen Ablauf eines Scriptes den Compiler an, innerhalb des aktuellen Blocks alles ab da nach den strikten Regeln zu kompilieren. So ist auch der entsprechende Teil der Fehlermeldung zu verstehen:

            "Execution of bla.pl aborted due to compilation errors."

            So könnte man auch folgendes machen:

            sub foo {  
              use strict;  
              my $foo = 42;  
              return $foo;  
            }  
              
            $bar = foo();  
            print $bar;
            

            Und es gibt keinen Fehler.

            ...der automagische Aufruf ...
            Hat das was mit den hier so oft erwaehnten Glaskugeln zu tun? ;)

            Nene, Perl hat schon einiges an Automagie ;)

            Siechfred

            --
            Ein Selbständiger ist jemand, der bereit ist, 16 Stunden am Tag zu arbeiten, nur um nicht 8 Stunden für einen Anderen arbeiten zu müssen.
            1. Hi,

              Ja, BEGIN ist insofern verwirrend als Name. Die von strict provozierten Fehler werden während der *Kompilierung* gezogen, nicht zur Laufzeit. Letztlich weist "use strict" im chronologischen Ablauf eines Scriptes den Compiler an, innerhalb des aktuellen Blocks alles ab da nach den strikten Regeln zu kompilieren.

              Das ist recht interessant.
              Also wird es praktisch vor der eigentlichen Ausführung schonmal "vorkompiliert"?

              Aber jetzt interessiert mich noch, was genau passiert, wenn ich ein Perl-Script ausführen lasse. Es ist ja irgendwie ne Mischung aus kompilierter- und Scriptsprache. Aber das werde ich am besten erstmal Google fragen.

              ...der automagische Aufruf ...
              Hat das was mit den hier so oft erwaehnten Glaskugeln zu tun? ;)

              Nene, Perl hat schon einiges an Automagie ;)

              Das denk ich mir auch, wenn ich sowas sehe.

              mfG,
              steckl

        2. Hallo Siechfred!

          Ja, use funktioniert ähnlich wie eine Präprozessoreinstellung, weil es wie ein BEGIN-Block so früh wie möglich, also noch während der *Kompilierung* ausgeführt wird, sodass der automagische Aufruf von import und die damit im strict-Pragma verbundene Manipulation des Kompilerverhaltens *ab diesem Zeitpunkt* wirkt.

          Ich lese mich gerade durch das Kapitel »Kompilierung« durch  (einige Passagen - auch aus den Kapitel IPC und Threads - muss ich aus mangelndem Background leider nur überfliegen, die nehme ich mir dann später wieder vor) und da ich also gerade bei der Behandlung von BEGIN, CHECK, INIT und END bin, kommt passend folgende Frage:

          use strict;

          zu Script-Beginn und

          BEGIN {
          require strict; # <- ist hier nicht require 'strict.pm'; besser?
          }

          irgendwo im Script, also auch am Ende, dürften, wie in Deiner allerersten Antwort das Selbe bewirken, nämlich eine »Strikt-Behandlung«?

          Viele Grüße aus Frankfurt/Main,
          Patrick

          --

          _ - jenseits vom delirium - _
          [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
          Nichts ist unmöglich? Doch!
          Heute schon gegökt?
          1. Re!

            use strict;

            zu Script-Beginn und

            BEGIN {
            require strict; # <- ist hier nicht require 'strict.pm'; besser?
            }

            Ein paar Zeilen weiter gelesen, und schon wäre die Frage nicht notwendig gewesen:

            <cite>Die use-Deklaration ist einfach ein BEGIN-Block mit bestimmtem Inhalt: Laden eines Moduls und Import von Namen in den lokalen Namensraum</cite>

            ...|

            Viele Grüße aus Frankfurt/Main,
            Patrick

            --

            _ - jenseits vom delirium - _
            [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
            Nichts ist unmöglich? Doch!
            Heute schon gegökt?
          2. use strict;

            zu Script-Beginn und

            BEGIN {
            require strict; # <- ist hier nicht require 'strict.pm'; besser?
            }

            irgendwo im Script, also auch am Ende, dürften, wie in Deiner allerersten Antwort das Selbe bewirken, nämlich eine »Strikt-Behandlung«?

            Ja, ab diesem Zeitpunkt resp. im aktuellen Block.

            BEGIN {
            require strict; # <- ist hier nicht require 'strict.pm'; besser?
            }

            Ups, das geht schief, der Grund steht in Struppis Antwort. Ansonsten ist es wurscht, ob du an dieser Stelle strict oder 'strict.pm' schreibst.

            Im ersten Fall wird ein '.pm' anghängt, im Modulnamen enthaltene '::' werden zu '/'. Das Ergebnis wird dann in @INC gesucht. Diese Erstzungen finden nicht statt, wenn du quotest, dann musst du das Modul exakt angeben, also mit Slash statt '::' und mit .pm hinten dran.

            Das hat was mit der Automagie von Perl zu tun ;)

            Siechfred

            --
            [NaN]