четверг, 23 июля 2009 г.

[comp.prog] C++0x: Concepts R.I.P.

Небольшая хронология событий:

  • сначала мне попадается статья о ситуации с развитием стандарта C++0x. В которой говорилось, что ни в одном из распространенных C++ компиляторов реализация концептов не сможет начаться раньше 2010-го года. Т.е. даже при самом удачном стечении обстоятельств, концепты реально появились бы только в 2011;
  • затем в news-группе digitalmars.D.announce Вальтер Брайт (автор компилятора Digital Mars C++ и языка D) сказал, что есть слухи о намерении выбросить концепты из языка. Вообще
  • ну и в завершении появились сообщения о том, что концепты таки выбросили (вот и вот).

Вот такие дела. С одной стороны грустно, т.к. огромный кусок работы был выброшен (пока, по крайней мере). Но с другой стороны:

  • я очень зауважал комитет по стандартизации C++. Люди сумели принять очень трудное решение;
  • это так же свидетельствует о том, что в комитете преобладает здравый смысл, а это вселяет надежду;
  • появляются шансы на более скорый выход как самого C++0x, так и компиляторов, в достаточной степени C++0x реализующих.

На мой взгляд, история с концептами доказала одну простую истину. Она была озвучена, если мне не изменяет мой склероз, Гради Бучем в книге по объектно-ориентированному анализу и проектированию: любая работающая сложная система может вырасти только из работающей простой системы. Т.е. для программного обеспечения есть только один путь развития – эволюционный. Революции не проходят. А добавление концептов в стандарт языка без наличия хотя бы одного работающего прототипа этой идеи – это как раз революция.

Хочется надеяться, что люди из комитета учтут опыт создания стандартов 1998-го года и C++0x в дальнейшем будут идти другим путем: небольшие ревизии стандарта каждые 3-5 лет, вместо больших ревизий раз в десять лет.

Ну и еще один вывод, уже личный. Приятно, что в этот раз я не пытался “бежать впереди поезда” и изучать стандарт до его принятия.

В заключение ссылки на описания концептов от Бъярна Страуструпа:
Specifying C++ Concepts
Symplifying the use of concepts

Update. Статья Б.Страуструпа о произошедшем: The C++0x "Remove Concepts" Decision. В ней так же можно найти ссылки на различные версии описаний концептов. И список того, что же будет в C++0x (т.е. уже в C++1x).

Еще один update: What Happened in Frankfurt? от Дуга Грегора (разработчика ConceptGCC, источник тут). Из его рассказа у меня сложилось впечатление, почему с концептами ничего не вышло -- было два разных направления, каждое из которых тянула и развивала своя группа. А компромиса в условиях комитета достичь не удалось (если такое вообще возможно).

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

1 комментирует...

А можно попросить коротко и по-русски изложить саму суть концептов? Исходя из того, что с понятием "шаблон" читатель уже знаком.

eao197 комментирует...

Сразу предупреждаю, что за концептами я следил издалека, поэтому всех тонкостей не знаю (в черновике стандарта концептам отводилось порядка 40 страниц). Объясню то, что сам понимаю.

Пусть у нас есть шаблонная функция:

template<class T> T square(T x)
{ return x * x; }

С ее помощь мы можем легко возводить в квадрат все, что нам потребуется:

square(1); // square<int>()
square(1.2); // square<double>()

Но в существующем C++ никто не запрещает нам написать так:

std::string a("abc");
square(a); // square<string>()

И получить при компиляции кучу маловразумительных ошибок. С которыми придется долго разбираться для того, чтобы понять, что тип string не может использоваться со square, т.к. для string не определен оператор умножения.

Концепты были призваны задавать ограничения типам параметров шаблонов. Чтобы компиляция обламывалась при попытке вызова square<string>(), а не при попытке компиляции square<string>(). И чтобы при этом были внятные сообщения о причине ошибки.

Достигаться это должно было посредством приблизительно такой нотации:

template<class T> where Multiplicable<T>
square(T x) {return x * x;}

Где Multiplicable -- это как раз имя концепта. А определяется концепт так:

concept Multiplicable<T> {
Var<T> x;
x * x;
}

Т.е. данный концепт задает условия: a) можно объявлять переменные типа T и b) переменные типа T можно перемножать.

С использованием концептов попытка вызова square<string> должна привести к сообщению о том, что тип string не удовлетворяет условиям концепта Multiplicable.

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

1 комментирует...

Спасибо. Укурка, конечно, та ещё. Но даже такая мера не заставит программистов поголовно описывать все необходимые концепты и возможно возникновение ошибок обоих упомянутых тобой типов.

eao197 комментирует...

Всем программистам эта фича, вероятно, и не нужна была. Но вот разработчики шаблонных библиотек (того же Boost-а) наверняка ее бы заюзали по самое нехочу.

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

Гораздо важнее в истории с концептами другое. Концепты -- это исключительно теоритическая идея. Пока нигде не было реализовано ничего подобного, чтобы посмотреть на практике, во что же это все выльется. При этом сама идея концептов успела трансформироваться из достаточно простой (как раз то, что я описал) в очень сложную (до concept_map-ов). И все равно разработчики концептов не были довольны тем, что получалось.

Т.е. на всю это бодягу было потрачено около 6-7 лет, но без однозначно хорошего результата. И здесь была опасность повторить ошибку прошлого стандарта -- включить в него раздел, который никогда не будет реализован (как exception specification и external templates). Но комитетчики молодцы, они смогли удержаться от такого решения. За что им огромный респект.

В принципе, в коммерческой разработке, когда есть один руководитель проекта, такое решение выглядит нормальным и очевидным -- если проект не укладывается в срок, то нужно резать избыточные его части. Но здесь же нет единоличного руководства, а есть куча индивидумов с разными намерениями и целями. И они все же смогли придти к такому важному решению.

bsivko комментирует...

> Любая работающая сложная система может вырасти только из работающей простой системы.

link recovery:

Любая работающая сложная система является результатом развития работавшей более простой системы... Сложная система, спроектированная "с нуля", никогда не заработает. Следует начинать с работающей простой системы".
(с) Gall, J. 1986. Systemantics: How Systems Really Work and How They Fail. Second Edition. Ann Arbor, MI: the General Systemantics Press, p.65.

eao197 комментирует...

2Boris: спасибо за точную ссылку.