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

new Chef[EmptyPizza]()

Я исправлю это в статье через минуту, но чтобы объяснить себя, на самом деле у меня были некоторые конструкторы в объекте case Chef, определяющие следующее:

def apply(): Chef[Pizza.EmptyPizza] = new Chef[Pizza.EmptyPizza]()

Затем я подумал, что не повредит их удалить, поскольку они не добавляли никаких дополнительных концепций, но, напротив, их было бы трудно прочитать любому разработчику, не использующему Scala. У меня также был конструктор Chef, определенный как частный.

Видите ли, моя ошибка связана с определением иерархии типов в Scala. Оказывается, в Scala есть тип, который является подтипом любого другого типа и называется Ничего :

В этом случае компилятор Scala пытается привязать каждую реализацию к наиболее конкретному из возможных типов. Поскольку компилятор совершенно не знает, какую привязку мы хотим установить в этих случаях, он выбирает Nothing.

Но это становится еще хуже. Поскольку Nothing является подтипом всего, то это также подтип FullPizza.

Затем, когда мы его строим, он просто работает.

Самый простой способ решить эту проблему - просто ограничить построение класса Chef, как я делал раньше: ограничить конфиденциальность конструктора Chef и построить его с помощью определенных конструкторов в сопутствующем объекте.

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

Я думаю, что я просто исправлю примеры шеф-повара в статье и отсылаюсь к этому комментарию для получения дополнительной информации.

На самом деле это прекрасный пример того, как вывод типов может быть довольно легко реализован на нашем пути, и мы этого не заметим.

Действительно хороший улов! Спасибо!