Я рассматриваю тип, аналогичный тем, которые определены в NamedArrays и Images. Предположим, я просто хочу по существу массив с куском метаданных, скажем, удобное для пользователя имя, которое я напишу в верхней части файла, когда я напишу массив на диск. (Эта деталь не имеет значения, я просто умудряясь примером.)Как избежать массового количества шаблонов в Юлии с новыми типами?
Так что я мог бы сделать
type MyNamedArray
data::Array
name::ASCIIString
end
function mywrite(f,x::MyNamedArray)
write(f,x.name)
write(f,x.data)
end
или что-то, и никакого другого поведения должны отличаться от поведения базового массива.
В моей голове это «очевидно», что я просто хочу, чтобы всякая существующая функция, работающая на массивах, работала на поле data
этого типа. На другом языке, например. Java Я мог бы просто подклассифицировать Array и добавить name
в качестве поля экземпляра в подкласс, который автоматически сохранит совместимость со всеми существующими операциями Array. Но в Julia, если я попробую решение, подобное выше, мне теперь нужно определить тонну больше функций, например. как @TimHoly и «davidavdav» сделали в связанных пакетах.
Конечно, я знаю, что принуждение выписывать некоторые из этих функций вручную полезно для понимания того, что вы не продумали. Например. в приведенном выше примере MyNamedArray
, можно было бы возразить, указав, что я не определил имя x::MyNamedArray * y::MyNamedArray
. Но что, если я просто не забочусь об этом, и хочу, чтобы код «просто работал», без большого количества шаблонов? (См., Например, цикл с символами для ввода новых определений методов in NamedArrays и вручную выписывания сотен строк определений in Images. Подавляющее большинство этих определений является шаблоном/«очевидным» определением.)
В частности, чтобы продолжить пример, который я привел , для MyNamedArray
значение по умолчанию может быть x*y
больше не является MyNamedArray
, т. е. поскольку каждая функция только по умолчанию использует «унаследованное» поведение применения одной и той же функции в базовых данных, мы можем просто забыть метаданные обо всех существующих ранее функциях.
Примечание: я нахожу ответ Томаса Ликена here проницательный, а также вопрос и ответы here.
Лучший синтез, который я могу придумать, - «вам просто нужно сосать его и выписать функции, или написать макрос, который сделает это за вас». Если это так, пусть будет так; Мне просто интересно, не хватает ли я лучшего варианта, особенно лучший способ разработать решение, чтобы сделать его более юлианским и избежать шаблона.
Много хороших предложений здесь; Я немного потрудился и отчитаюсь. Благодаря! – Philip
Я думаю, что возникает связанный с этим вопрос о логической связи между интерфейсами реализации и подтипированием. На других языках с явными интерфейсами это уже ясно. В Джулии это просто различие «диспетчеризация против времени исполнения»? Другими словами, если вы объявляете тип подтипом супертипа, то методы, определенные в супертипе, также отправят также подтип (если вы их не переопределили). Но тогда реализация этих методов может завершиться неудачно во время выполнения, если вы не внедрили неформальный интерфейс? – Philip
Да, это [утиная печать] (http://stackoverflow.com/questions/4205130/what-is-duck-typing). Он действительно просто перемещает ошибку на один уровень - вместо того, чтобы бросать MethodError для 'sum (:: MyNamedArray)', вы получаете MethodError, когда он пытается итерировать или индексировать свой массив в реализации суммы. Это ошибка во время выполнения без ошибок. –