PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [Perl] "Forwarding" von Funktionen via AUTOLOAD



illu
23-06-2005, 19:30
Hi,

als erstes gleich mal der (auf's Wesentliche reduzierte) Code:



package UI;

use Curses;

sub new { bless {}, shift }

sub AUTOLOAD {
my ($self, @args) = @_;

use vars qw($AUTOLOAD);

print "$AUTOLOAD(@args)\n"; # gibt beim Testen "UI::DESTROY()" aus, und nicht, wie erwartet, "UI::initscr()"?
$AUTOLOAD =~ s/.*:://;

eval "$AUTOLOAD(@args)"; # oder "Curses::$AUTOLOAD"; ? Hat beim Testen keinen Unterschied gemacht
}

package main;

my $ui = UI->new();
$ui->initscr();
# usw.


Ich wuerde also gerne in der UI-Klasse nicht definierte Methodenaufrufe direkt an Curses.pm "weiterleiten".
Bei dem Programm, was ich gerade schreibe, moechte ich also einfach alles UI-maessige ueber meine UI-Klasse machen, also auch die Interaktion mit Curses.
(Zwischenfrage: ist das ueberhaupt eine gute Idee so, in Hinblick auf gutes Programmdesign, oder sollte ich es ganz anders angehen?)

Wieso funktioniert es aber nicht so wie oben?
Beim Testen (mit "use warnings") die()t es mit der folgenden Ausgabe:



Curses function 'initscr' called with too many arguments at ./test.pl line n.

michael.sprick
24-06-2005, 10:05
Hi,


# gibt beim Testen "UI::DESTROY()" aus, und nicht, wie erwartet, "UI::initscr()"?

halbe Wahrheit ;)

Wenn Du in MAIN ein UI-Objekt erzeugst, dann wird am Ende von MAIN bzw. am Ende des blockes, in dem das Objekt erzeugt wurde IMMER versucht, einen Destruktor aufzurufen. ->DESTROY(). Der Unterschied zu anderen Methoden ist, dass es keinen Syntaxfehler gibt, wenn diese Methode nicht existiert.

Insgesamt hast Du als 3 Methoden Aufrufe:

UI->new()
UI->initscr();
UI->DESTROY();

Die Destroy Methode solltest Du auf jeden Fall noch in der UI Klasse implementieren - kann ja leer sein. Andernfalls würde der Autoloader versuchen, die Methode von Curses aufzurufen, was vermutlich nicht gewünscht ist ;)

Ansonsten versuch doch mal statt

use Curses;

use lib Curses;

zu benutzen...



# oder "Curses::$AUTOLOAD"; ? Hat beim Testen keinen Unterschied gemacht
Besser Curses::$AUTOLOAD, denn sonst funktioniert das nur mit Methoden, die von Curses exportiert werden...

hth, michael

illu
25-06-2005, 08:57
Ok, das mit der leeren DESTROY-Funktion ist eine gute Idee dann.
Aber das Seltsame ist ja, dass print ueberhaupt kein "initscr" ausgibt, sondern *nur* das "DESTROY".
Ansonsten hilft leider nichts von dem, was du sagtest. Sonst noch eine Idee? Wenn nicht, muss ich's halt anders machen.

michael.sprick
25-06-2005, 10:45
Aber das Seltsame ist ja, dass print ueberhaupt kein "initscr" ausgibt, sondern *nur* das "DESTROY".
Ne - das ist richtig so. curses exportiert die initscr() Methode - das bedeutet, sie ist jetzt in UI verfügbar. Der AUTOLOADER greift also nicht.

Aber genau da liegt glaubich auch das Problem...
vergiss das mit dem "use lib Curses".
Ehrlichgesagt kam es mir auch schon ein wenig komisch vor, denn damit beeinflusst man eigentlich nur die Reihenfolge, in der die Module geladen werden.
Versuch doch mal so:



package UI;

use Curses qw();

sub new { bless {}, shift }

sub AUTOLOAD {
my $self = shift(@_);
my @args = @_;
$" = ',';

our $AUTOLOAD;
$AUTOLOAD =~ s/.*:://;
print "Method UI::$AUTOLOAD(@args) not found...forwarding!\n";
eval("Curses::$AUTOLOAD(@args)");
}

sub DESTROY
{
print "Destruktor...\n";
}

package main;

my $ui = UI->new();
$ui->initscr();