Перегрузка против Переопределения в Юлии - PullRequest
0 голосов
/ 29 мая 2018

Я не знаком с Джулией, но чувствую, что заметил, что она позволяет вам определять функции несколько раз с разными подписями, такими как this :

FK5Coords{e}(ra::T, dec::T) where {e,T<:AbstractFloat} = FK5Coords{e, T}(ra, dec)
FK5Coords{e}(ra::Real, dec::Real) where {e} =
   FK5Coords{e}(promote(float(ra), float(dec))...)

Для меня это выглядитнапример, это позволяет вам вызывать FK5Coords с двумя разными сигнатурами.

Поэтому мне интересно (а), верно ли это, если Джулия разрешает перегрузку функций , как это, и (b) если Джулия допускает в функции что-то вроде super, что может привести к перегрузке.И (c), как выглядит пример фрагмента кода Джулии, который показывает (1) перегрузку в одном примере и (2) переопределение в другом.

Причина, по которой я спрашиваю, заключается в том, что мне интереснокак Джулия решает проблему перегрузки как super, так и функции, потому что оба требуют повторного определения функции, и кажется, что вам придется пометить ее метаданными или что-то, чтобы сказать «в этом случае я переопределяю» или «в этомcase I overloading ".

Примечание. Если это не был пример перегрузки, то (из Википедии) я предположил, что именно это поддерживает Джулия (по этим направлениям):

// volume of a cylinder
double volume(const double r, const int h)
{
    return 3.1415926*r*r*static_cast<double>(h);
}

// volume of a cuboid
long volume(const long l, const int b, const int h)
{
    return l*b*h;
}

1 Ответ

0 голосов
/ 30 мая 2018

Так что мне интересно (а), если это правда, если Джулия позволяет перегрузить функции, подобные этой

Джулия позволяет вам писать разные версии одной и той же функции (разные "методы"для функции), которые отличаются по типу / количеству аргументов.Это очень похоже на перегрузку, за исключением того, что перегрузка обычно означает, что вызываемая функция определяется на основе типа аргументов во время компиляции, тогда как в Julia это определяется на основе типа аргументов во время выполнения.Это обычно называется динамической отправкой.Посмотрите этот пример C ++ , чтобы увидеть, чего не хватает в перегрузке, и диспетчеризация дает вам.

(b) если Джулия разрешает что-то вроде супер в функции, которая, похоже, будет конфликтовать с перегрузкой. Я спрашиваю, потому что мне интересно, как Джулия решает проблему наличия обоих супери перегрузка функции, потому что оба требуют повторного определения функции, и кажется, что вам придется пометить ее метаданными или что-то, чтобы сказать «в этом случае я переопределяю» или «в этом случае я перегружаю».

Я не уверен, почему вы думаете, что перегрузка будет конфликтовать с super.В C ++ переопределение подразумевает наличие одинаковых номеров и типов аргументов, тогда как перегрузка требует, чтобы число или тип аргументов были разными.Компиляторы достаточно умны, чтобы легко различать эти два случая, и AFAICT C ++ может иметь метод super, несмотря на то, что имеет как перегрузку, так и переопределение, за исключением того, что он также имеет множественное наследование.Я полагаю (с моим ограниченным знанием C ++), что множественное наследование является причиной того, что C ++ не имеет вызова метода super, не перегруженного.

В любом случае, если вы откроете объектно-ориентированную шторку и посмотритев сигнатуры методов вы увидите, что все переопределения - это действительно определенный тип перегрузки: Dog::run(int dist, int dir) может переопределять Animal::run(int dist, int dir) (предположим, что Dog наследует от Animal), но это эквивалентно перегрузке функции run(Animal a, int dist, int dir) с помощью run(Dog d, int dist, int dir)определение.(Если бы run была виртуальной функцией, это была бы динамическая диспетчеризация вместо перегрузки, но это отдельное обсуждение.)

В Юлии мы делаем это явно, поэтому определения будут run(d::Dog, dist::Int, dir::Int) и run(a::Animal, dist::Int, dir::Int).Однако в Julia вы можете наследовать только от абстрактных типов, поэтому здесь супертип Animal был бы абстрактным типом, поэтому вы не можете вызвать второй метод с экземпляром Animal - определение второго метода действительно является кратким способомсказать «вызовите этот метод для любого экземпляра некоторого конкретного подтипа Animal, если только у этого подтипа нет своего отдельного определения метода» (что в данном случае делает Dog).Я не знаю ни одного простого способа вызова второго метода run(Animal... из первого run(Dog..., который был бы эквивалентен вызову super.

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

(c), какой примерфрагмент кода Julia выглядит следующим образом: (1) перегрузка в одном примере и (2) переопределение в другом.

Первый отправленный вами фрагмент кода является примером использования dispatch (вот чтоЮля использует вместо перегрузки).Для другого примера давайте сначала определим наш базовый тип и функцию:

abstract type Vehicle end
function move(v::Vehicle, dist::Float64)
  println("Moving by $dist meters")
end

Теперь мы можем создать другой метод этой функции для отправки («перегрузить» ее) следующим образом:

function move(v::Vehicle, dist::LightYears)
  println("Blazing across $dist light years")
end

Мы также можем сделать объектно-ориентированный стиль «переопределить» (хотя на уровне языка это просто рассматривается как другой метод для отправки):

struct Car <: Vehicle
  model::String
end
function move(c::Car, dist::Float64)
  println("$model is moving $dist meters")
end

Это эквивалент переопределения Vehicle.move(float dist) в производномкласс как Car.move(float dist).

И, черт возьми, функция громкости из вопроса:

# volume of a cylinder
volume(r::Float64, h::Int) = π*r*r*h
volume(l::Int, b::Int, h::Int) = l*b*h;

Теперь правильный метод volume для вызова будет определяться на основе количества (и типа) переданных аргументов.(и тип возвращаемого значения автоматически определяется компилятором, Float64 для первого метода и Int для второго).

...