Viele Module stellen einfach Funktionen zur Verfügung, wie z.B. List::Util
die Funktionen first
, all
, any
und noch weitere. Diese kann man in seinen eigenen Code importieren (oder aus Sicht von List::Util
dementsprechend exportieren).
Auch in eigenen Modulen kann man so einen Exportmechanismus sehr einfach bereitstellen. Dafür gibt es z.B. die Module Exporter
und Exporter::Tiny
. Wer es lieber selbst in die Hand nimmt, fügt in seinem Modul eine Funktion import
ein.
In der Regel werden Module mit use Modulname;
eingebunden. Diese Zeile Code ist im Prinzip das gleiche wie
BEGIN {
require Modulname;
Modulename->import();
}
Im Modul, das die Funktionen zur Verfügung stellt, könnte es so aussehen:
package ExportHello;
use v5.38;
use base 'Exporter';
our @EXPORT = qw(hello);
sub hello { say 'Hello World!' };
Damit wird bei einem use ExportHello
die Funktion hello importiert. Das hat einen großen Nachteil: Der Namensraum wird zugemüllt
mit Funktionen, die evtl. gar nicht von anderem Code aufgerufen werden soll.
package ImportHello;
use ExportHello;
hello();
Das führt hello bereits beim Einbinden des ImportHello-Moduls aus. Wenn man das Modul jetzt verwendet:
$ perl -I. -MImportHello -e 1
Hello World!
Die Funktion hello kann aber auch über den Namensraum ImportHello aufgerufen werden:
$ perl -I. -MImportHello -e 'ImportHello->hello()'
Hello World!
Hello World!
Es sieht also so aus, als ob ImportHello die Funktion hello bereitstellt. Was aber gar nicht Sinn des use ExportHello
war.
Mit Perl 5.38 ist es jetzt möglich, solche Exporte lexikalisch zu machen, so dass ImportHello zwar die Funktion hello nutzen kann, aber von außen
sieht man diese Funktion nicht.
Über das pragma builtin werden einige Funktionalitäten bereitgestellt wie z.B. in Bezug auf Booleans – und jetzt auch die Funktion export_lexically.
package ExportHello;
use v5.38;
use experimental 'builtin';
use builtin 'export_lexically';
export_lexically hello => sub { say 'Hello World!' };
Damit ist die Funktion hello nur noch in ImportHello nutzbar, aber nicht mehr von außen
:
$ perl -I. -MImportHello -e 'ImportHello->hello()'
Hello World!
Can't locate object method "hello" via package "ImportHello" at -e line 1
Aber nicht nur Funktionen können so lexikalisch exportiert werden, sondern auch beliebige Variablen:
package ExportAll;
use v5.38;
use experimental 'builtin';
use builtin 'export_lexically';
my ($scalar, @array, %hash);
export_lexically
'$year' => \$scalar,
'@talks' => \@array,
'%info' => \%hash,
check => sub {
say "Year: $scalar, Talks: @array"
}
;
Die Variablen $scalar
, @array
und %hash
werden unter anderem Namen exportiert. Der Code, der dieses Modul nutzt, hat dann die Variablen $year
, @talks
und %info
sowie die Funktion check
zur Verfügung. Wichtig bei der Definition ist die Verwendung der einfachen Anführungszeichen.
Wird das Modul ExportAll jetzt verwendet, können die Variablen und die Funktion verwendet werden:
use ExportAll;
$year = 2023;
@talks = qw(Perl_5.38 Playwright);
check();
In dem Skript werden die Variablennamen $year und @talks verwendet, obwohl die an keiner Stelle erstellt wurden. Im Modul ExportAll wird auf die Moduleigenen Variablen $scalar und @array zugegriffen.
Auch bei den Variablen gilt, dass diese lexikalisch sind und von außen
nicht darauf zugegriffen werden kann.
Permalink: /2023-07-24-exportweltmeister-perl