Абстрактные типы и наследование в Julia

#inheritance #julia

#наследование #джулия

Вопрос:

Предположим, я определяю функцию для абстрактного типа A в Julia:

 abstract A
function mysum(a::A)
  a.x   a.y
end
  

Неявно любой подтип должен иметь поля x и y, чтобы эта функция работала. Таким образом, функции, определенные в A, задают требования к подтипам. Эти функции могут быть написаны где угодно, и можно представить ситуацию, когда функции намного сложнее, а требования сложнее определить. Есть ли какой-либо способ объявить требования, которые должен иметь подтип абстрактного типа, помимо того, что они просто неявно исходят из функций?

Похоже, это связано с Julia # 6975, но если это не связано с этим, мог бы кто-нибудь разъяснить разницу.

Наконец, почему кто-то хочет использовать объединение типов вместо абстрактного типа.Абстрактный тип является более гибким и расширяемым, объединение типов исправлено. Например

Почему это:

 type A
  x
end

type B
  x
end

typealias C Union{A,B}
  

Вместо этого:

 abstract C

type A <: C
  x
end

type B <: C
  x
end
  

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

1. Первый вопрос: Я не думаю, что в настоящее время существует способ достичь этого, но это лежит в основе дискуссий о добавлении черт в язык. Вы уже нашли один вопрос, обсуждающий это, и я полагаю, что он включен в неофициальную дорожную карту после версии 1.0 (по крайней мере, я видел, как это упоминалось). Типы объединения могут использоваться (среди прочего) для добавления методов к типам, которые не имеют общего супертипа. Абстрактные типы хороши, но вы не всегда можете включить все свои типы в общую иерархию, и часто вам приходится добавлять методы в коллекции типов, которые вы не определяли самостоятельно.

2. @DNF Спасибо, это проясняет мое замешательство! Если вы хотите написать это как ответ, я буду рад принять.

3. Пожалуйста, разбейте это на два вопроса.

4. @Oxinabox на это уже дан ответ, вы хотите, чтобы я открыл 2 других вопроса?

5. @mikev3 не в этот раз, оно того не стоит (я написал этот комментарий, не обновляя страницу). Но для будущих вопросов было бы неплохо разбить их. Это означает, что если кто-то может ответить на одну часть действительно хорошо, но на другую плохо, они вроде как не застряли. И это позволяет сфокусировать каждый пост.

Ответ №1:

Первый вопрос: Я не думаю, что в настоящее время существует способ достичь этого, но это лежит в основе дискуссий о добавлении черт в язык. Вы уже нашли один вопрос, обсуждающий это, и я полагаю, что он включен в неофициальную дорожную карту после версии 1.0 (по крайней мере, я видел, как это упоминалось).

Я думаю, что рекомендуемый способ реализации того, что вы ищете, — это что-то вроде этих строк (обратите внимание, что type это устарело и заменено на struct ):

 abstract type A end

struct B <: A
    x
    y
end

struct C <: A
    w
    z
end

prop1(b::B) = b.x
prop2(b::B) = b.y
prop1(c::C) = c.w
prop2(c::C) = c.z  # changed from prop2(c::C)=c.w

mysum(a::A) = prop1(a)   prop2(a)
  

То есть, вместо того, чтобы требовать, чтобы B и C имели одинаковые поля, вы реализуете методы, которые определяют их поведение. Тогда фактические имена полей остаются внутренними деталями реализации каждого конкретного типа.

Что касается типов объединения, их можно использовать (среди прочего) для добавления методов к типам, которые не имеют общего супертипа. Абстрактные типы хороши, но вы не всегда можете включить все свои типы в общую иерархию, и часто вам приходится добавлять методы в коллекции типов, которые вы не определяли самостоятельно.

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

1. Это именно то, что мне было интересно, спасибо! Если B и C используют один и тот же тип информации, но не совсем одинаковые имена полей, то как мне реализовать общий метод? Вы это прояснили.

2. 1 за использование методов для доступа к полям. Я сделал ложное предположение, предполагая, что каждый подтип моего абстрактного типа, который мне когда-либо понадобится, будет иметь одинаковые поля core 5, реализованные одинаковым образом, плюс некоторые другие. Это оказалось неправильным и сделало мой код уродливым. Теперь я думаю о доступе к полю чего-либо, что объявлено как абстрактный тип, чтобы быть антишаблоном. (Речь шла о добавлении для этого правила Lint.jl)

3. @DNF Если я не ошибаюсь, это выглядит очень похоже на классы типов в Scala, Rust или Haskell. Функции prop1 и prop2 являются классами типов, а методы prop1(b::B) , prop1(c::C) и т.д. Являются реализациями этих классов типов, это примерно правильно или я что-то пропустил-понял?

4. Этот ответ был отредактирован 27 апреля 2021 года, но он не был обновлен полностью: abstract A будет ошибка при публикации версии v1.0 Julia. Это должно гласить abstract type A end . Я предложил эту правку, но mods отклонили ее. @DNF не могли бы вы обновить его?

5. Конечно. Спасибо за совет.