4. Проблема Алмаза. Окончание
Начало
Продолжение
Так в чём же состоит Проблема Алмаза? Не в наследовании несовместимого, а в выборе, какой унаследованный член использовать. Ситуация усложняется, когда мы вводим состояние в базовый класс. Нам нужно решить, хотим ли мы иметь независимые состояния для каждого подкласса (обычное наследование) или разделять его между подклассами (виртуальное наследование). Если мы делимся состоянием, оно может легко сломаться (поскольку две разные реализации используют одни и те же переменные). Если нет, нам нужно указать, какие переменные мы имеем в виду в самом низком подклассе.
В C# и Java проблема решается ошибкой времени компиляции. Но в других языках есть другие решения, например в Scala приоритет получает член «крайнего правого» унаследованного класса.
Проблема Алмаза в Java и C# с первого дня
По сути Проблема Алмаза была в Java и C# с самого начала. Как мы уже говорили, проблема состоит в том, чтобы решить, какому из членов отдать приоритет. Например:
class A {
public string foo(long l) => "Long";
public string foo(double d) => "Double";
}
Что выведет следующий код? A a = new A();У нас есть два метода с разными сигнатурами. Мы хотим вызвать метод и передать недопустимое значение - значение другого типа. Однако Java и C# достаточно «умны», и просто приводят значение к типу, который им больше нравится (в данном случае -
Console.WriteLine(a.foo(123));
long).По сути, это та же Проблема Алмаза, что и раньше. У нас есть две вещи, и мы не можем решить, какую из них использовать. При реализациях интерфейса по умолчанию языки выдают ошибку компиляции, но при перегрузке метода они просто выбирают один метод вместо другого.
Это, кстати, может привести к нарушению совместимости. Представьте, что кто-то добавит ещё один метод
foo(int i). Что будет с вашим кодом? Раньше int приводился к long, но после добавления нового метода приведение не требуется, и будет вызван новый метод. Это нарушает совместимость.Итого
Хотя правильно сказать, что в Java и C# нет множественного наследования, лучше иметь в виду, что существует много уровней наследования, и мы должны быть конкретными. Мы можем унаследовать реализацию начиная с C# 8 — это множественное наследование или нет?
Хотя правильно сказать, что до 8 версии языка не было Проблемы Алмаза, по сути, проблема существует в перегрузке методов. И это имеет те же последствия.
Стоит помнить, как, казалось бы, совершенно разные языковые элементы приводят к аналогичным проблемам. Мы все «боимся» Проблемы Алмаза, но не боимся перегрузки методов. Более того, считаем что это классная функция, пока однажды не нарушим совместимость.
Источник: https://blog.adamfurmanek.pl/2021/02/06/types-and-programming-languages-part-4/