Объясняется ли разница между этими двумя оценками свертыванием констант?

Учитывая эти две оценки, которые изменяют только Module::FOO() и FOO().

# Symbols imported, and used locally.
eval qq[ 
  package Foo$num;
  Module->import();
  my \$result = Module::FOO() * Module::FOO();
] or die $@;

# Symbols imported, not used locally referencing parent symbol.
eval qq[ 
  package Foo$num;
  Module->import();
  my \$result = FOO() * FOO();
] or die $@;

почему верхний блок должен занимать существенно меньше места? Сценарий и вывод воспроизведены ниже,

Скрипт

package Module {
  use v5.30;
  use warnings;
  use constant FOO => 42; 
  use Exporter 'import';
  our @EXPORT = ('FOO');
}


package main {
  use v5.30;
  use autodie;
  use warnings;

  $|=1;
  say "Our PID is $$";

  for my $num ( 0..1e5 ) { 
    eval qq[ 
      package Foo$num;
      Module->import();
      my \$result = Module::FOO() * Module::FOO();
    ] or die $@;
    eval qq[
      package Foo$num;
      Module->import();
      my \$result = FOO() * FOO();
    ] or die $@;
  }

  say "DONE";

  _debug();

}

sub _debug {
  open my $fh, "<", "/proc/$$/status";
  while ( <$fh> ) { 
    next unless /Rss/;
    print;
  }
}

Полученные результаты

Пакет (пространство имен) квалифицирован

RssAnon:      78896 kB
RssFile:       5220 kB
RssShmem:         0 kB

Местный импорт

RssAnon:     168180 kB
RssFile:       5496 kB
RssShmem:         0 kB

person Evan Carroll    schedule 28.01.2021    source источник


Ответы (1)


Это результат постоянного сворачивания внутри Perl. Это можно продемонстрировать на следующем примере из haarg по irc.freenode.net/#perl,

use strict;
use warnings;

package Module {
  use constant FOO => 42;
  use Exporter 'import';
  our @EXPORT = ('FOO');
}

my $subs = {
  loc => sub {
    package Foo;
    Module->import();
    my $result = FOO() * FOO();
  },
  fq => sub {
    package Foo;
    Module->import();
    my $result = Module::FOO() * Module::FOO();
  },
};

use Data::Dumper;
$Data::Dumper::Deparse = $Data::Dumper::Indent = 1;
print Dumper($subs);

Это приведет к тому,

$VAR1 = {
  'loc' => sub {
      package Foo;
      use warnings;
      use strict;
      'Module'->import;
      my $result = FOO() * FOO();
  },
  'fq' => sub {
      package Foo;
      use warnings;
      use strict;
      'Module'->import;
      my $result = 1764;
  }
};

Вы можете видеть, что у одного из них есть,

my $result = FOO() * FOO();

В то время как другой имеет,

my $result = 1764;

Вы можете получить постоянное свертывание как в том случае, если модуль объявлен, так и импорт выполняется на этапе компиляции (в случае подкомпиляции) или перед выполнением в случае stringy-eval, например

BEGIN {

    package Module {
      use constant FOO => 42;
      use Exporter 'import';
      our @EXPORT = ('FOO');
    }
    package Foo { Module->import() }

}
person Evan Carroll    schedule 28.01.2021