Siechfred: Konzept der Namensräume; Global, Dynamic und Lexical Scope

Beitrag lesen

Es ist zugegebenermaßen nicht einfach mit den Namensräumen, ich habe selbst noch damit zu kämpfen...

Dann will ich mal versuchen, etwas Licht ins Dunkel zu bringen.

Namespace vs. Scope

Zunächst muss unterschieden werden zwischen Namespace und Scope. Während Namespace der Namensraum ist, über den eine Variable "identifiziert" wird, bedeutet Scope zum Einen, wo eine Variable gültig ist und zum Anderen nach welchen Regeln (local vs. my, my vs. our). Den Namensraum einer Variablen notiert man durch Voranstellen von 'namespace::', ein Script hat immer den Namensraum 'main::'. Die Angabe des Namensraumes entfällt, wenn er eindeutig ist oder sich auf das aktuelle Package bezieht.

Symboltabellen, package-Anweisung

Perl speichert intern alle Symbole (Skalare, Arrays, Hashes, Subs usw.) in internen Symboltabellen. Jeder Namensraum hat eine eigene Symboltabelle, sodass man sagen kann, dass Namespace vereinfacht der Name der Symboltabelle ist, zu dem das Symbol gehört. Die package-Anweisung macht also untechnisch nichts anderes, als zu prüfen, ob es bereits eine Symboltabelle mit dem Namen gibt, den die Funktion als Argument mitbekommt, sie im Bedarfsfall anlegt und dem Script sagt, dass es bis zur nächsten package-Anweisung resp. bis zum Ende des Scriptes diese Symboltabelle verwenden soll. Daneben haben alle Symboltabellen, die das selbe Script betreffen *und* in der Hierarchie oberhalb des aktuellen packages liegen, weiter Gültigkeit, insbesondere 'main'.

Global Scope

Perl bietet traditionell die Möglichkeit, Variablen global zu definieren:

{ $foo = 'bar'; }  
print $foo;

$foo ist global und damit überall im Script sichtbar. Dieses Verfahren ist sehr fehleranfällig und erschwert die Suche nach Problemen, da bei der Modifikation globaler Variablen unerwartete Ergebnisse auftreten können, und dann sucht man verzweifelt nach der Stelle, wo die ungewollte Modifikation stattfand. Dies ist der Hauptgrund, weshalb man das strict-Pragma verwenden sollte - um eben solche fehleranfälligen Strukturen zu vermeiden.

Dynamic Scope

Der nächste Schritt ist der sog. Dynamic Scope, repräsentiert durch local. Dabei wird nichts anderes gemacht, als für den umschließenden Block eine Variable anzulegen, die nur dort Gültigkeit hat. Gibt es eine globale Variable, wird sie im Block kopiert und sämtliche Manipulationen innerhalb des Blocks werden ungültig, wenn der Block beendet ist. Gibt es keine gleichnamige globale Variable, wird sie als quasi-lokale Variable angelegt:

$foo = 'global';  
  
{  
  local $foo = 'lokal';  
  print $foo;  # lokal  
}  
  
print $foo;  # global

Oft wird local mit my gleichgesetzt, das ist aber grundfalsch! Mein Lieblingsartikel hierzu sagt ganz lapidar: "Always use my; never use local." :)

Stellt sich natürlich die berechtigte Frage, wofür der Dynamic Scope gut sein soll. Diese Frage kann man ganz einfach mit einem kleinen Codeschnipsel beantworten (aus perlfaq5):

my $input;  
  
{  
  local(*INPUT, $/);  
  open INPUT, 'datei.txt' || die "can't open: $!";  
  $input = <INPUT>;  
}

Es gibt nämlich in Perl verschiedene, vom System vorgegebene globale Variablen, so z.B. $/ für den Record Separator (also das Zeichen, das beim Einlesen eine Zeile beendet). Knackpunkt ist die local-Anweisung, die diese globale Variable kopiert. Da keine Wertzuweisung erfolgt, ist ihr Wert undef, sodass man die Datei in einem Rutsch in den Skalar $input einlesen kann. Wird der Block geschlossen, ist die lokale Kopie im Datennirvana, der global definierte Wert bleibt während der ganzen Operation unangetastet.

Lexical Scope

Der eleganteste und am wenigsten fehleranfällige Weg, Variablen zu deklarieren, ist der Lexical Scope. Innerhalb eines Namensraumes gibt es bestimmte Regeln, nach denen Variablen sichtbar sind. Außerhalb des umgebenden Blocks oder Namensraums sind sie nur sichtbar, wenn sie mittels our deklariert wurden, wurden sie mittels my deklariert, sind sie nach außen unsichtbar. Nach innen sind beide Varianten für alle nachgeordneten Blöcke und Namensräume sichtbar (das ist übrigens auch die Fehlerquelle des Threadstarters):

use strict;  
my $foo = 'declared in main';  
  
package bar;  
$foo .= ' and modified in bar';  
my $foo_loc = 'local in bar';  
our $foo_glob = 'local in bar but visible outside';  
  
package main;  
# wir wollen keinen Scriptabbruch provozieren  
no strict 'vars';  
print defined $foo ? $foo : 'undef';  # declared in main and modified in bar  
print defined $bar::foo_loc ? $bar::foo_loc : 'undef';  # undef  
print defined $bar::foo_glob ? $bar::foo_glob : 'undef';  # local in bar but visible outside

Hier kann man sehr schön die Auswirkungen des lexikal scopes sehen. $foo ist im Namensraum 'main' deklariert und von da an im gesamten Script sichtbar, also auch im Package bar. Die Variable $foo_loc ist via my als lokal innerhalb des Packages bar deklariert mit der Besonderheit, dass sie außerhalb von bar nicht sichtbar ist, während $foo_glob zwar auch lokal in bar ist, aber durch die Deklaration via our nach außen sichtbar ist. Um auf $foo_glob außerhalb von bar zuzugreifen, notiert man den Namensraum davor (also $bar::foo_glob). Jede Manipulation an $foo_glob, auch außerhalb von bar, hat Auswirkungen auch innerhalb von bar:

use strict;  
  
package bar;  
our $foo_glob = 'local in bar but visible outside';  
  
sub show_bar {  
  return $foo_glob;  
}  
  
package main;  
$bar::foo_glob .= ', tricky, isn\'t it?';  
print bar::show_bar;

Faszinierend, was dabei herauskommt, oder? ;)

Natürlich kann man den lexical scope auch ohne strict-Pragma verwenden, er ist *nicht* an dieses Pragma gebunden! Allerdings nimmt strict dem Programmierer die Prüfung ab, ob er bei allen verwendeten Symbolen die Regeln des lexical scope beachtet hat und warnt bei Verstößen bis hin zum Programmabbruch.

So, ich hoffe, dass ich etwas Licht ins Dunkel bringen konnte, ansonsten frage gerne nochmal nach.

Siechfred

0 80

Frage zu packages

Connie
  • perl
  1. 0
    Patrick Andrieu
    1. 0
      Connie
      1. 0
        Connie
        1. 0
          Patrick Andrieu
          1. 0
            Struppi
            1. 0
              Patrick Andrieu
              1. 0
                Struppi
                1. 0
                  Patrick Andrieu
            2. 0
              Connie
              1. 0
                Connie
    2. 0
      Connie
    3. 6

      Konzept der Namensräume; Global, Dynamic und Lexical Scope

      Siechfred
      1. 0
        Connie
      2. 0
        Connie
        1. 0
          Patrick Andrieu
          1. 0
            Connie
            1. 0
              Patrick Andrieu
              1. 0
                Connie
                1. 0
                  Connie
                  1. 0
                    Struppi
                    1. 0
                      Connie
                      1. 0
                        Struppi
                        1. 0
                          Connie
                          1. 0
                            Struppi
                            1. 0
                              Connie
                              1. 0
                                Struppi
                                1. 0
                                  Connie
                                  1. 0
                                    Struppi
                                    1. 0
                                      Connie
                                      1. 0
                                        Struppi
                                      2. 0
                                        Struppi
                                      3. 0
                                        Patrick Andrieu
                                        1. 0
                                          Struppi
                                          1. 0
                                            Kurt
                                            1. 0
                                              Struppi
                                              1. 0
                                                Kurt
                                                1. 0
                                                  Struppi
                                                  1. 0
                                                    Kurt
                                                    1. 0
                                                      Kurt
                                                      1. 0
                                                        Thomas
                                                        1. 0
                                                          Siechfred
                                                          1. 0
                                                            Kurt
                                                            1. 0
                                                              Siechfred
                                                              1. 0
                                                                Kurt
                                                        2. 0
                                                          Kurt
                                                          1. 0
                                                            Kurt
        2. 0
          Siechfred
      3. 0
        Patrick Andrieu
        1. 0
          Kurt
      4. 0
        Kurt
        1. 0

          my erzeugt keinen Packagevariablen!

          Kurt
        2. 0
          Siechfred
          1. 0
            Siechfred
            1. 0

              Konzeption...

              Patrick Andrieu
              • menschelei
            2. 0
              Kurt
              1. 0
                Siechfred
                1. 0
                  Kurt
  2. 0
    Kurt
    1. 0
      Kurt
    2. 0
      Struppi
      1. 0
        Kurt
      2. 0
        Interessierter Leser
        1. 0
          Interessierter Leser
          1. 0

            Coping with Scoping

            Kurt
        2. 0
          Kurt
  3. 0

    Zusammenfassende Darstellung, Kritik willkommen!

    Siechfred
    1. 0
      Kurt
      1. 0
        Struppi
        1. 0
          Kurt
          1. 0
            Struppi
            1. 0
              Thomas
              1. 0
                Struppi
            2. 0
              Kurt
              1. 0
                Struppi
                1. 0

                  1 Klasse= 1 Modul ?

                  Kurt
                  1. 0
                    Struppi
      2. 0
        Siechfred
        1. 0
          Thomas
        2. 0
          Kurt