[Cologne-pm] Tk::pack statt pack()

A. Pagaltzis pagaltzis at gmx.de
Mon Jun 20 08:35:48 PDT 2005


* Falky <perl at falky.de> [2005-06-20 16:00]:
> Dabei klappt allerdings die Notation ohne den Pfeil -> nicht
> immer

Vergiss diese Notation. Sie ist ziemlich unzuverlässig, die
Regeln dafür, wann sie wie geparst wird, ändern sich so ziemlich
nach Lust und Laune, je nachdem was vorher in der Datei
drinstand. Jeder bessere Perl-Programmierer wird dir davon
abraten. Die Probleme mit Konstrukten wie »print STDERR $foo«
sind dir hoffentlich hinlänglich oft begegnet, dass du das auch
selber weisst.[1]

Du kannst zwar versuchen, ohne explizite Syntax zu arbeiten,
wirst dir damit aber keinen gefallen tun.

Was denn nun besser daran ist,

    bar $foo ( $baz );

statt

    $foo->bar( $baz );

zu schreiben, weiss ich auch nicht – unter der Haube passiert
immer dasselbe, du programmierst so oder so objektorientiert.

Und gerade bei GUIs wirst du nicht um OOP herumkommen. Selbst
prozedurale GUI-APIs sind letztlich nur (spärlich) verdeckte OOP,
weil schon das eigentliche Modell einer Oberfläche mit
geschachtelten Darstellungs- und Bedienelementen einfach an sich
schon objektorientiert ist.

>   $button->pack(side=>'top'); #klappt, gefällt mir aber nicht
>   pack $button (side=>'top'); #klappt nicht
>   Tk::pack $button (side=>'top'); #klappt wieder, ist aber auch nicht schön

Klappt nur zufällig, denn es ist nicht dasselbe wie

    $button->pack( side => 'top' );

weil evtlle Vererbung nicht mehr berücksichtigt wird. Du musst
also bei dieser Schreibweise wissen, welche Klasse oder
Oberklasse welche Methode implementiert. Wenn gar die Methode in
Wirklichkeit nur über den AUTOLOAD-Mechanismus vorgespiegelt
wird, wird es noch komplizierter, und dein Code muss *noch* mehr
über Implementierungsdetails der verwendeten Module wissen.

> Kann ich dem Interpreter irgendwie sagen, 'Vergiss
> (vorrübergehend) die Standardfunktion pack()'?

Mit »&pack()« sagst du Perl, dass du die gleichnamige
benutzerdefinierte Funktion statt der eingebauten Funktion
meinst. Wie gut das mit der indirekten Objekt-Notation, die du
verwenden willst, funktioniert, weiss ich nicht, weil ich die nie
verwende.

> Mir ist auch deshalb nicht so ganz klar, was ich suche, weil
> ich die interne logik nicht ganz kapiere. Da pack 'nur' eine
> Methode ist, wird sie mit use nicht importiert (wimni). Daher
> müsste ich sie vieleicht besser über irgent ein Default-Widget
> ansprechen, vieleicht
>   *pack = *Tk::Default->pack ???

Wenn du »$foo->bar()« sagst, erwartet Perl, dass »$foo« eine
»gesegnete« (blessed) Referenz ist. Eine solcherart gesegnete
Referenz unterscheidet sich darin von einer normalen, dass sie
ausser der Referenz selbst auch einen Paketnamen wie »Tk::Button«
trägt. Rufst du darauf eine Methode auf, etwa »pack«, passieren
drei Dinge:

1. Perl sucht im Paket »Tk::Button« nach der Methode »pack«.
2. Findet es sie dort nicht, schaut es im Array
   »@Tk::Button::ISA« nach, ob es Oberklassen dieser Klasse gibt,
   und sucht, falls vorhanden, reihum in diesen Klassen ebenfalls
   nach der Methode.
3. Hat es die Methode nun endlich gefunden, wird sie wie eine
   normale Funktion aufgerufen, mit dem Unterschied, dass die
   Referenz als erster Parameter an die Funktion übergeben wird.

Da fehlen jetzt noch Details, vor allem was AUTOLOAD betrifft,
aber die sind erstmal unerheblich.

Was du versuchen willst, kann jedenfalls einfach schon deswegen
nicht funktionieren, weil sämtliche funktionierenden Ansätze die
Suche in Schritt 2 übergehen müssen. Die lässt sich nur durch
einen echten Methodenaufruf nutzen (es sei denn, du programmierst
den Suchalgorithmus nach, aber das wollen wir mal nicht hoffen).

> Kann mir irgend wer auf die Spünge helfen?
> 
> ein anderes Problem?
> 
>   $opt{-text} = 'pong';
>   $opt{-command} = [$App=>'destroy'];
>   $button = Button $App %opt;
> bzw
>   $App->Button(-text => 'OK',-command => [$App=>'destroy'])->pack
> 
> Ich hatte verstanden, -command würde eine code-Referenz (ein
> Callback) bekommen. Das währe dann aber doch [\$App->destroy],

Nein, das wäre »sub { $App->destroy() }«. Codereferenzen zeigen
immer nur auf Funktionen; sie können keine Methodenaufrufe sein,
weil für einen solchen ein Objekt (also eine gesegnete Referenz)
nötig ist. Ein Methodenaufruf ist immer mit einem symbolischen
Lookup verbunden, harte Referenzen können das nicht leisten.

> wohingegen die => Notation nix anderes ist als eine Liste. (ich
> vermute zwar, das dass noch irgenwo in den Tiefen von perldoc
> Tk... steht, naja mal abwarten)

Ja, Tk macht hier einen Sonderfall: wenn das, was du übergibst,
keine Codereferenz, sondern eine Arrayreferenz ist, dann wird das
erste Element als das Objekt betrachtet, das zweite als der
Methodenname, und die weiteren als Parameter. Dh., Tk sorgt
dafür, dass das:

    [ $button, 'pack', side => 'top' ]

letztlich intern so interpretiert wird:

    $button->pack( side => 'top' )

sodass du dir den ständigen Einsatz von »sub {}« sparen
kannst.[2] Ich halte den Nutzen solcher Sperenzchen jedenfalls
für zweifelhaft, eben weil sie, wie in deinem Fall zu sehen, zu
Verwirrung führen, wenn jemand, der die Sonderwürste von Tk nicht
kennt, solchen Code liest.

> Ach so ja, ich heiße bürgerlich Katrin Falkenberg, benutze Perl
> (bisher) vor allem für kleinere Scripts auf unserem Server und
> bin 37. Noch Fragen?

Hallo Katrin. :-)



[1] Perl 6 wirft übrigens all diese Regeln über Bord, weil sie
    nie funktioniert haben, und ändert die Notation so, dass sie
    immer eindeutig parsbar ist, indem dieses »indirekte Objekt«
    durch einen folgenden Doppelpunkt markiert wird.

[2] Das ist übrigens keine Zauberei, sondern kann auch einfach so
    bewerkstelligt werden:

        my $callback = [ $foo, 'bar', baz => 42 ];

        if( UNIVERSAL::isa( $callback, 'ARRAY' ) ) {
            my ( $obj, $meth, @param ) = @$callback;
            $obj->$meth( @param );
        }
        else {
            $callback->();
        }


Gruss,
-- 
#Aristoteles
*AUTOLOAD=*_=sub{s/(.*)::(.*)/print$2,(",$\/"," ")[defined wantarray]/e;$1};
&Just->another->Perl->hacker;


More information about the Cologne-pm mailing list