четверг, 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 комментариев:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    ОтветитьУдалить
  5. >Найти и обнаружить, что это - класс, созданный с прицелом под реализацию в наследниках, после чего искать, что же это за фабрика и что она на самом деле 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();
    }

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

    ОтветитьУдалить