Почему DRY не считается хорошей вещью для объявлений типов? - PullRequest
4 голосов
/ 18 ноября 2009

Кажется, что люди, которые никогда не посмеют вырезать и вставить код, не будут иметь проблем с указанием типа чего-либо снова и снова. Почему в качестве хорошей практики не подчеркивается, что информация о типе должна объявляться один раз и только один раз, чтобы вызвать как можно меньший волновой эффект во всем исходном коде, если тип чего-либо изменяется? Например, используя псевдокод, который заимствует из C # и D:

MyClass<MyGenericArg> foo = new MyClass<MyGenericArg>(ctorArg);

void fun(MyClass<MyGenericArg> arg) {
    gun(arg);
}

void gun(MyClass<MyGenericArg> arg) {
    // do stuff.
}

Vs.

var foo = new MyClass<MyGenericArg>(ctorArg);

void fun(T)(T arg) {
    gun(arg);
}

void gun(T)(T arg) {
    // do stuff.
}

Похоже, что второй вариант гораздо менее хрупок, если вы измените имя MyClass, измените тип MyGenericArg или иным образом решите изменить тип foo.

Ответы [ 5 ]

2 голосов
/ 18 ноября 2009

Я не думаю, что вы обнаружите много разногласий с вашим аргументом о том, что последний пример "лучше" для программиста. Есть много особенностей дизайна языка, потому что они лучше для разработчика компилятора!

См. Scala для одного воплощения вашей идеи.

Другие языки (такие как семейство ML) значительно продвигают вывод типов и создают целый стиль программирования, в котором тип чрезвычайно важен, гораздо больше, чем в языках, подобных C (См. Little MLer для нежного введения.)

1 голос
/ 18 ноября 2009

Это не считается плохой вещью вообще. Фактически, сопровождающие C # уже немного продвигаются к сокращению утомительного шаблона с ключевым словом var, где

MyContainer<MyType> cont = new MyContainer<MyType>();

в точности соответствует

var cont = new MyContainer<MyType>();

Хотя вы увидите много людей, которые будут спорить против var, что показывает, что многие люди не знакомы со строго типизированными языками с выводом типов; вывод типа ошибочно принят за динамическую / мягкую типизацию.

1 голос
/ 18 ноября 2009

Повторение может привести к более читаемому коду, а иногда может потребоваться в общем случае. Я всегда видел фокус DRY больше в дублировании логики, чем в повторении буквального текста. Технически вы также можете исключить «var» и «void» из нижнего кода. Не говоря уже о том, что вы указываете область с отступом, зачем повторять скобки?

Повторение также может иметь практические преимущества: например, анализ с помощью программы проще, если оставить «void».

(Тем не менее, я все еще полностью согласен с вами в том, что вы предпочитаете "var name = new Type ()", а не "Type name = new Type ()".)

0 голосов
/ 18 ноября 2009

Это плохо. Эта тема была упомянута в Google's Go language Techtalk .

0 голосов
/ 18 ноября 2009

Альберт Эйнштейн сказал: «Все должно быть сделано как можно проще, но не на немного проще».

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

Если ваша цель состояла в том, чтобы просто пройти через аргумент без проверки его типа, то правильный тип был бы Object, а не T.

Объявления типов предназначены для того, чтобы упростить жизнь программиста, перехватывая ошибки во время компиляции, а не сбой во время выполнения. Если у вас слишком сложное определение типа, вы, вероятно, не понимаете свои данные. В вашем примере я бы предложил добавить fun и gun к MyClass, а не определять их отдельно. Если fun и gun не применяются ко всем возможным типам шаблонов, то они должны быть определены в явном подклассе, а не как отдельные функции, которые принимают аргумент шаблонного класса.

Обобщения существуют как способ обернуть поведение вокруг более конкретных объектов. List, Queue, Stack, это отличные причины для Generics, но в конце концов, единственное, что вы должны делать с чистым Generic, - это создавать его экземпляр и вызывать для него методы. Если вы действительно чувствуете необходимость делать больше, чем это с Generic, то вам, вероятно, нужно встроить ваш Generic класс в качестве объекта экземпляра в класс-оболочку, который определяет поведение, которое вам нужно. Это делается по той же причине, по которой вы встраивали примитивы в класс: потому что сами по себе числа и строки не передают семантической информации об их содержимом.

* * Пример тысяча двадцать-один: * * 1 022

Какую семантическую информацию передает List? Просто вы работаете с несколькими тройками целых чисел. С другой стороны, List, где цвет имеет 3 целых числа (красный, синий, зеленый) с ограниченными значениями (0-255), передает намерение, что вы работаете с несколькими цветами, но не дает подсказки относительно того, является ли список заказал, позволяет дубликаты или любую другую информацию о цветах. Наконец, Палитра может добавить эту семантику для вас: палитра имеет имя, содержит несколько цветов, но не имеет дубликатов, и порядок не важен.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...