在子模块中重用父符号

Reuse parent symbols in child module

我正在寻求在子模块中重复使用与其父模块相同的 role/class 名称。你知道,就像一个专业。

目标是能够通过简单地将顶部的 use Dan 更改为 use Dan::Pandas 来为父系列和子系列变体重复使用相同的脚本代码。

我尽量坚持角色而不是 class 组合,以便可以将行为应用于其他对象,例如。 class GasBill does Series;

这是 MRE:

me@ubuntu:~/spike# tree
.
├── lib
│   ├── Dan
│   │   └── Pandas.rakumod
│   └── Dan.rakumod
└── spike.raku

Dan.rakumod:

  1 unit module Dan;
  2 
  3 role Series is export {
  4     method no { "no" }
  5 }

Pandas.rakumod:

  1 unit module Dan::Pandas;
  2 
  3 use Dan;
  4 
  5 role Series does Dan::Series is export {
  6     method yo { "yo" }
  7 }

spike.raku:

  1 use lib './lib';
  2 use Dan::Pandas;
  3 
  4 my $s = Series.new;                  #version 1                      
  5 #my $s = Dan::Pandas::Series.new;    #version 2 "fqm"
  6 
  7 say $s.no, $s.yo, $s.^name;

我的版本 1 说:

No appropriate parametric role variant available for 'Dan::Series':
    Ambiguous call to '(Dan::Series)'; these signatures all match:
      (::$?CLASS ::::?CLASS Mu $)
      (::$?CLASS ::::?CLASS Mu $)
  in block <unit> at spike.raku line 4

我的版本 2 说:

Could not find symbol '&Series' in 'Dan::Pandas'
  in block <unit> at spike.raku line 5

我相信 raku 确实有办法做到这一点,但如果我能解决这个问题该死!

如果我的理解正确,你不会 need/want 在最终模块中使用 non-specialized 角色(也就是说,你没有使用定义的 Series in Dan.rakumod in spike.raku – 你只使用在 Pandas.rakumod 中定义的专门的 Series)。对吗?

如果是这样,解决方案很简单:只是不要 export 来自 Dan.rakumodSeries – 它仍然是 our 作用域(角色的默认值)所以您仍然可以在 Pandas.rakumod 中像现在一样使用它 (Dan::Series)。但是,由于它没有导出,因此不会与 non-prefixed Series.

产生名称冲突

TL;DR 您需要一个解决方案来避免两个角色具有相同的全名。

高尔夫

role R {}
role R {}
R.new

显示:

No appropriate parametric role variant available for 'R':
    Ambiguous call to '(R)'; these signatures all match:
      (::$?CLASS ::::?CLASS Mu $)
      (::$?CLASS ::::?CLASS Mu $)

(有关错误消息的更多讨论,请参阅 Gut-referencing warning when composing stubbed role。)

一个解决方案

  1. Dan.

    • Dan.rakumod:

      unit module Dan;
      
      role Series is export { method no { "no" } }
      
    • spike.raku:

      use lib '.';
      
      use Dan;
      
      my $s = Series.new;
      
      .say for $s.?no, $s.?yo, $s.^name;
      
    • 运行 spike 显示:

      no
      Nil
      Dan::Series
      
  2. 介绍Dan::Pandas.

    • 更改 Dan 以便变体模块可以 use 无需 它们 导入 Dan 未限定 Series 符号进入其词法范围。

      (否则 Dan 的不合格 Series 符号最终会出现在它们的词法范围 以及 它们的 own 不合格的 Series 符号,你会得到“模糊调用”错误。)

    • Dan:

      unit module Dan;
      
      role Series is export { method no { "no" } }
      
      class Dan::Variant-Export-Dummy-Type is export(:Variant-Exports) {}
      

      更改是最后一行,带有新导出标记的虚拟声明。 (以更简洁的方式介绍新标签留给读者作为练习。)

    • Dan::Pandas:

      unit module Dan::Pandas;
      
      use Dan :Variant-Exports;
      
      role Series does Dan::Series is export { method yo { "yo" } }
      

      更改是使用带有 use Dan ... 语句的新 :Variant-Exports 标签。这会阻止 DanSeries 角色以该非限定名称导入 Dan::Pandas.

  3. 用户程序现在将作为 expected/wanted。

    • 只需将spike.raku中的use语句改成:

      use lib '.';
      
      use Dan::Pandas;
      
      my $s = Series.new;
      
      .say for $s.?no, $s.?yo, $s.^name;
      
    • 运行 只是用户程序的这个变化:

      no
      yo
      Dan::Pandas::Series
      
    • 请注意,使用这些模块的程序不需要了解 :Variant-Exports 标记。这只是 Dan 模块和 Dan::Pandas 等模块的内部细节,可以避免本答案开头显示的意外角色变体重复问题。

我的解决方案

听取@codesections [可以在没有 is export 的情况下使用 FQM] 和 @raiph [您可以使用例如限定导出的建议] is export(:ALL)],那么 - 是的 - 有一种巧妙的方法可以做到这一点。

即。 https://docs.raku.org/language/modules#Exporting_and_selective_importing

事实证明,这是低级接触(只需更改两行),而且正如我最初希望的那样,这是 raku 设计师所预料到的。

这是我的 OP 调整后的代码...

Dan.rakumod:

  1 unit module Dan;
  2 
  3 role Series is export(:ALL) {    #<== added the selective export
  4     method no { "no" }
  5 }  

Pandas.rakumod(无变化):

  1 unit module Dan::Pandas;
  2 
  3 use Dan;
  4 
  5 role Series does Dan::Series is export {
  6     method yo { "yo" }
  7 }  

spike.raku:

  1 use lib './lib';
  2 #use Dan::Pandas;     #\ either of these work
  3 use Dan :ALL;         #/ <== use :ALL to get 'Series'
  4 
  5 my $s = Series.new;
  6 
  7 say $s.no, $s.yo, $s.^name;  #No such method 'yo' if Pandas not used