четверг, 29 октября 2009 г.

[comp.prog.flame] Все таки я против автоматического вывода типов

В современных языках программирования стало модно использовать автоматический вывод типов (type inference). Веяние сие даже до C++ добралось – в C++0x ключевое слово auto при декларации переменной будет означать автоматический вывод типа:

auto result = std::shared_ptr< MyType >( new MyType() );

Очень неоднозначно я к этой штуке отношусь. Был у  меня опыт изучения чужих исходников на D и Scala, где эти фичи использовались в полный рос – мрак. Документации приходится перелопачивать гораздо больше, чем в случае с аннотациями типов. Особенно в случаях, когда переменной присваивается неизвестно что:

auto writer = getDevice().getConduit();

Что за Device возвращается, что потом за Conduit оказывается во writer-е – без поллитры не разберешься.

А вот свежий пример: потребовалось мне в старом исходнике обнаружить места использования некоторой структуры. Нет проблем – контекстным поиском по файлу все эти места обнаруживаются на раз. В простом FAR-овском просмоторщике файлов. А если бы я использовал вывод типов? Да застрелиться бы можно было бы, если бы под рукой не было мощной IDE, в которой должна была бы быть возможность найти все использования конкретного типа.

Так что, наверное, где-то вывод типов хорош (скажем, чтобы принять результат boost::bind или анонимный тип в LINQ). Но чем меньше, тем лучше. Имхо, конечно.

5 комментариев:

Евгений Железников комментирует...

auto writer = getDevice().getConduit(); Что за Device возвращается, что потом за Conduit оказывается во writer-е – без поллитры не разберешься.

Ок, берем плюсы: чем отличается использование typedef'ов всяких составных типов, чьи объявления равномерно разбросаны по коду?
Скажем, какой-нибудь IndirectWorker w = GlobalFactory.get().CreateIndWorker();

Или автор кода должен писать читабельно для посторонних в ущерб удобству собственной работы?

Евгений Охотников комментирует...

В плюсах IndirectWorker можно найти в проекте контекстным поиском. А в D приходится сначала искать тип возвращаемого значения метода getDevice(), затем смотреть, что возвращает getConduit(). Телодвижений больше оказывается.

Евгений Охотников комментирует...

>Или автор кода должен писать читабельно для посторонних в ущерб удобству собственной работы?

Именно так. Простота чтения кода важнее простоты его написания.

К сожалению, в C-подобных языках изначально разработчик обречен на дублирование имен. Но, например, в Eiffel или в Zimbu ситуация совсем другая. Там и декларации типов делаются, и писать нужно не много.

Евгений Железников комментирует...

В плюсах IndirectWorker можно найти в проекте контекстным поиском.

Найти и обнаружить, что это - класс, созданный с прицелом под реализацию в наследниках, после чего искать, что же это за фабрика и что она на самом деле creates.

Это, конечно, утрированно, смысл вот в чем: ди не обязывает пользоваться auto; видимо, автор кода считал это уместным, а это уже вопрос к автору, не к языку - и на плюсах можно навести туману.
Примеров, уверен, вы и сами можете пару страниц привести.

Именно так. Простота чтения кода важнее простоты его написания.

Что там было про "вот, бл*" при написании очередной обязаловки, диктуемой яп?

scope cont = GetSomeCont;
foreach(ind, val; cont) {}

Вот это - быстно и удобно, и ежели работа идет не в команде с четким style guide (или любыми другими договоренностями), все посторонние идут лесом.

Евгений Охотников комментирует...

>Найти и обнаружить, что это - класс, созданный с прицелом под реализацию в наследниках, после чего искать, что же это за фабрика и что она на самом деле creates.

Вы говорите не о том. Есть выражение:

auto w = getDevice().getConduit();

Какой тип у w? Какие методы у объекта w можно вызывать? Без документации на getDevice и на возвращаемый им тип (в худшем случае еще и на какой-то из его наследников) это не определить.

Если же записано:

MyDeviceConduit w = getDevice().getConduit();

то все понятно сразу.

Более того, компилятор будет мне давать по рукам, если MyDeviceConduit не совместим с возвращаемым getConduit типом. В месте обращения к getConduit().

>Вот это - быстно и удобно, и ежели работа идет не в команде с четким style guide (или любыми другими договоренностями), все посторонние идут лесом.

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

Вывод типов в ряде случаев имеет смысл. Скажем, в шаблонном коде:

template< class T > void put_data( T & terminal ) {
auto conduit = terminal.getDevice().getConduit();
conduit.write( data_header );
conduit.flush();
}

Только есть у меня сомнения, что вывод типов будут применять настолько избирательно.