【问题标题】:Class symbol introduction due to EVALFILE由于 EVALFILE 的类符号介绍
【发布时间】:2021-08-24 07:38:39
【问题描述】:

类名在EVALFILE 之后的范围内可用,而文档可能另有说明。

EVALFILEstates 的文档:

啜饮指定的文件并评估它。在 Blob 解码、作用域、$lang 参数和 $check 参数方面的行为与 EVAL 相同。当 $check 不为​​ True 时,计算文件中最终语句产生的值。

EVALstates 的文档:

由于词法范围内的符号集在编译后是不可变的,因此 EVAL 永远不能将符号引入周围的范围。

我的输入文件是:

class SomeClass {
    method a () { "In SomeClass method a"; };
}

sub some-routine () {
    "Some routine";
}
> my $f = EVALFILE("/tmp/eval-bug.raku");
&some-routine

> $f()
Some routine

> some-routine()
===SORRY!=== Error while compiling:
Undeclared routine:
    some-routine used at line 1

以上三个执行符合文档,但以下不符合:

> SomeClass.a()
In SomeClass method a

symbol 是不是只表示例程名而不是类名?或者这是一个错误?

【问题讨论】:

    标签: eval raku rakudo


    【解决方案1】:

    由于词法作用域中的符号集在编译后是不可变的,EVAL 永远不能将符号引入周围作用域

    这里的关键词是“词法作用域”。然而,类在默认情况下不是词法范围的(与例程不同),而是包范围。这意味着他们默认引入了一个全局名称。如果你改为写:

    my class SomeClass {
        method a () { "In SomeClass method a"; };
    }
    

    然后这声明了一个词法范围的类,不会引入全局名称,因此它不会安装在EVALFILE之外的任何地方。

    至少对我来说,文档似乎是正确的;它明确提到了词法作用域,并且“周围作用域”一词也带有文本(因此是词法)作用域的含义。但是,它可能会提到 EVALFILE 中声明的包范围的东西将被全局安装。

    【讨论】:

      【解决方案2】:

      在我看来这是两件事的结合:1. 子例程 some-routine 未导出,2. REPL 中的范围问题。

      第一个可以通过两种方式修复:

      our sub some-routine() {
      

      sub some-routine() is export {
      

      第二个是,在 REPL 的当前状态下,不是真正可修复的(我已经尝试过了,但我的所有修复都在其他情况下引入了问题)。 REPL 当前实现为在您输入的每一行上执行EVAL,同时尝试与下一个共享任何先前EVAL 的元素。在运行时的当前状态下,完全共享是不可能的,这是人们报告的有关 REPL 的许多问题的原因。

      在 RakuAST 分支上的工作还意味着如果你愿意的话,让解释器的状态更加“客观化”,从而允许EVALs 之间更好的状态共享,从而更好的 REPL。但这至少需要几个月的时间才能登陆 Rakudo。

      【讨论】:

      • IMO,虽然 REPL 可能存在一些问题,但在这种情况下是正确的。
      • 即使在ouris export 之后,符号some-routine 也不会被导出。文件说不应该。我的问题是为什么要导出类名。
      猜你喜欢
      • 1970-01-01
      • 2017-01-03
      • 2016-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-11
      • 1970-01-01
      相关资源
      最近更新 更多