2016-06-07 2 views
7

Я рассматриваю тип, аналогичный тем, которые определены в 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.

Лучший синтез, который я могу придумать, - «вам просто нужно сосать его и выписать функции, или написать макрос, который сделает это за вас». Если это так, пусть будет так; Мне просто интересно, не хватает ли я лучшего варианта, особенно лучший способ разработать решение, чтобы сделать его более юлианским и избежать шаблона.

ответ

5

Вы можете получить большую часть пути путем простого подкласса AbstractArray: http://docs.julialang.org/en/latest/manual/interfaces/#abstract-arrays. Фактически, вы можете сделать один лучший и подкласс DenseArray, который дополнительно требует определения функции stride (и, возможно, pointer) ... позволяя вашему настраиваемому массиву работать с BLAS. Это всего лишь несколько методов, которые вам нужно определить. Это не на 100%, поскольку многие авторы все еще склонны слишком ограничивать методы, чтобы принимать только Array, когда они могут легко принять все AbstractArrays. За последние два года это значительно улучшилось, и это все еще улучшается.

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

+0

Много хороших предложений здесь; Я немного потрудился и отчитаюсь. Благодаря! – Philip

+0

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

+0

Да, это [утиная печать] (http://stackoverflow.com/questions/4205130/what-is-duck-typing). Он действительно просто перемещает ошибку на один уровень - вместо того, чтобы бросать MethodError для 'sum (:: MyNamedArray)', вы получаете MethodError, когда он пытается итерировать или индексировать свой массив в реализации суммы. Это ошибка во время выполнения без ошибок. –

Смежные вопросы