Проблема при использовании роли между двумя модулями - PullRequest
0 голосов
/ 09 сентября 2018

Я делаю модуль, который имеет многомодульный файл, и столкнулся с этой проблемой при использовании роли в другом модуле.

Например, у нас есть два модуля Foo и Bar, и в каждом модуле есть роль.

module Foo { 
    role foo is export {

    }  
}

module Bar { 
    import Foo; 

    role bar is export does foo {

    }
} 

import Foo;
import Bar;

sub f(foo \k) { }

f(bar.new);

Я думал, что код в порядке, но Ракудо сказал, что думает, что bar не foo, и отказывается компилировать.

Что здесь не так?

Ответы [ 3 ]

0 голосов
/ 10 сентября 2018

Символ foo после import не =:= до Foo::foo и не принимает последнее в умном совпадении. Это кажется мне ошибкой и предположительно связано с тем, что происходит:

module Foo {
  role foo is export { }
  .say for foo.^name, Foo::foo.^name,
           Foo.WHICH, foo.WHICH, Foo::foo.WHICH,
           foo.isa(Foo::foo),
           Foo::foo.isa(foo),
           foo.does(Foo::foo),
           Foo::foo.does(foo),
           foo ~~ Foo::foo,
           Foo::foo ~~ foo,
}
import Foo;
.say for foo.^name, Foo::foo.^name,
         Foo.WHICH, foo.WHICH, Foo::foo.WHICH,
         foo.isa(Foo::foo),
         Foo::foo.isa(foo),
         foo.does(Foo::foo),
         Foo::foo.does(foo),
         foo ~~ Foo::foo,
         Foo::foo ~~ foo,

Foo::foo
Foo::foo
Foo|U64545472
Foo::foo|U64545856
Foo::foo|U64545856
False
False
True
True
True
True
Foo::foo
Foo::foo
Foo|U64545472         <^-- all good so far
Foo::foo|U64545616    <--- uhoh
Foo::foo|U64545856
False
False
True
True
True
False                 <-- presumably a consequence of uhoh

Я сообщу об ошибке в ближайшие пару дней, если никто не побьет меня, и никто не покажет, почему это не ошибка.

0 голосов
/ 10 сентября 2018

Это похоже на ошибку для меня. Некоторое дальнейшее расследование:

module Foo {
    role Bar is export {}
}

module Quux {
    import Foo;
    constant Barr = Bar;
    role Baz does Bar is export {}
    role Bazz does Foo::Bar is export {}
}

import Foo;
import Quux;

# these are all the same: 
say Foo::EXPORT::ALL::Bar.WHICH;
say Quux::Barr.WHICH;
say Bar.WHICH;

# but different from our original type object!?!
say Foo::Bar.WHICH;

# now it gets weird:
say Baz ~~ Bar;           # True
say Baz.new ~~ Bar;       # False
say Baz ~~ Foo::Bar;      # False
say Baz.new ~~ Foo::Bar;  # True

# however, these all 'work':
say Bazz ~~ Bar;          # True
say Bazz.new ~~ Bar;      # True
say Bazz ~~ Foo::Bar;     # True
say Bazz.new ~~ Foo::Bar; # True

На данный момент кажется, что лучше всего извлекать новые роли только из полностью определенной общедоступной версии роли другого модуля вместо экспортированной: при экспорте создается новый объект типа, который странным образом взаимодействует с умной проверкой соответствия / проверки типа ...

0 голосов
/ 10 сентября 2018

Дайте мне посмотреть, смогу ли я направить @raiph и ответить на этот вопрос наилучшим возможным способом. Здесь есть несколько ошибок.

Использование import

Основным вариантом использования import является именно тот, который вы здесь делаете; описано в документации . Однако лучше поместить модули в разные файлы (с тем же именем, что и у модуля) и вместо этого перейти на use. use, который импортирует и включает все в пространство имен. use загружается (через need) и затем импортирует модуль ровно один раз.

Сохранить фигурные скобки, используя единицу измерения

unit - это в основном синтаксический сахар для сохранения скобок. Итак, первые два файла станут:

Foo.pm6

unit module Foo;

  role foo is export {
} 

Bar.pm6

unit module Bar;

use Foo; 

role bar is export does foo {}

use из Foo импортирует символ foo напрямую, и его можно использовать в качестве роли.

Что такое роль

И последнее, но не менее важное: роль, которую он играет, - это буквально декларация "делает". Это не декларация "есть". Так что bar может do foo, но это не foo. Что делает последний файл примерно таким:

use-foo-bar.p6

use Foo;
use Bar;
sub f(bar \k) { }
f(bar.new);

Обратите внимание, что я использовал bar \k вместо foo \k. Если бы я не сделал, ошибка будет: Type check failed in binding to parameter 'k'; expected Foo::foo but got Bar::bar (Bar::bar.new)

Вернуться к исходному сообщению

То, что было не так, было просто вложенным объявлением, которое должно было быть:

sub f(bar \k) { }

Из-за того, что объясняется в последнем разделе выше. Однако мне нужно было немного изучить остальную часть программы, чтобы выяснить это.

...