Dart: как обойти ромбовидный узор с помощью миксинов?

#dart #mixins

#dart #микшины

Вопрос:

Есть ли способ решить проблему с ромбами при использовании миксинов в Dart? Взгляните на следующий простой пример:

 class M1 {
  String sayHello() => "hello M1";
}
class M2 {
  String sayHello() => "hello M2";
}
class S {
  String sayHello() => "hello S";
}
class C extends S with M1, M2 {}

main() {
  C c = new C();
  print(c.sayHello());
  print((c as M1).sayHello());
}
  

Вывод:

 hello M2
hello M2
  

Если вы вызываете «sayHello» на c, это зависит от порядка миксинов в объявлении класса
C, какая из реализаций выполняется. Всегда используется реализация последнего микшина в списке. Это вряд ли является явным и часто может быть делом случая. Хуже того: реализация суперкласса C всегда скрыта.
Приведение к типу ничего не меняет, что, конечно, согласуется с общей философией Dart, согласно которой тип среды выполнения не играет роли при выполнении кода. Тем не менее, было бы хорошо, если бы были какие-либо средства для явного выбора между различными реализациями. Есть ли такая возможность?

Комментарии:

1. Я не уверен, о чем вы просите. Это также относится к обычному наследованию. Я думаю, что порядок миксинов явный, хотя он такой же, как порядок обычного наследования. Для обычного наследования вы можете использовать, super которое еще не доступно для миксинов. Я думаю, что это основная проблема. Команда Dart знает об ограничениях миксинов, и есть планы по их устранению, но, как всегда, они не предоставляют никакой информации, когда это произойдет.

2. Ситуация отличается от «обычного» наследования, поскольку множественное наследование в Dart невозможно, не так ли? Проблема, которую я вижу, заключается в том, что я не могу явно выбирать между различными реализациями «sayHello» в том месте, где вызывается функция. Это по-другому решается в C , где можно указать вызов функции именем объявляющего класса (если я правильно помню свои старые дни C ).

3. Нет, это не так. Что я пытался объяснить, так это то, что (new M2() as M1).sayHello() при использовании обычного наследования (например, sayHello() , M1 ) это M2 также вызывало бы не class M1 extends S {} реализацию в class M2 extends M1 {} , а ту, которая есть в в, а не в в).

4. Вы правы в том, что отсутствие super в миксинах ухудшает ситуацию, поскольку вы не можете разрешить конфликт в дочернем классе путем явной пересылки в тот или иной миксин или суперкласс.

5. Хорошо, понял. Приведение также не помогает выбирать между реализацией в родительском и дочернем классах. Таким образом, в этом отношении проблема возникает независимо от миксинов. Но это не делает его лучше 🙂

Ответ №1:

Короче говоря: нет.

Вы не можете решить проблему с ромбовидным шаблоном в Dart, потому что у Dart нет множественного наследования, поэтому у него нет проблемы (или функции).

Добавление миксинов поверх класса — это совершенно обычное одиночное наследование, а реализация класса Dart всегда представляет собой единую цепочку вплоть до объекта. Единственное, что делают миксины, — это позволяют одним и тем же элементам встречаться более чем в одной цепочке.

Это также означает, что нет способа получить доступ к переопределенным элементам выше по цепочке. Вы можете получить доступ только к самому верхнему объявлению или, как функция-член, к самому верхнему объявлению вашей суперцепи (используя super.foo() ).

Комментарии:

1. Я не понимаю вашего «и реализация класса Dart всегда представляет собой единую цепочку вплоть до Object. Единственное, что делают миксины, — это позволяют одним и тем же элементам встречаться более чем в одной цепочке. »