Comments 65
Картинка с чуваком которого выкидывают из окна:
— Итак, какой сделаем новый сервис пак?
— Поддержка COBOL!
— Новые фичи из С++17!
— А может быть более полная поддержка С++11 в 2010 и 2013 студии?
* выкидывание из окна *
— Итак, какой сделаем новый сервис пак?
— Поддержка COBOL!
— Новые фичи из С++17!
— А может быть более полная поддержка С++11 в 2010 и 2013 студии?
* выкидывание из окна *
+30
:)
Да ладно, посмотрите список остальных фич — там десяток фиксов именно для С++11.
Да ладно, посмотрите список остальных фич — там десяток фиксов именно для С++11.
+6
MS молодцы, все это давно уже есть в шарпе, читая все это возникает дежавю.
-4
Это уже 40 лет есть в Smalltalk. Возникает дежавю.
+9
Самое интересное, что в самом Smalltalk-е этого нет. Но есть в библиотеке. На самом деле, есть континуации — и тоже не в языке, в библиотеке. А через континуации легко делаются сопрограммы. (Впрочем, можно и без континуаций — через процессы.)
Так вот, на что хочу обратить внимание:, когда кому-то понадобились континуации, он просто их взял и сделал сам — без внесений изменений в язык! Причем сделал все это, уйдя с Ruby, так как не смог на тот момент добиться внесения тех самых континуаций в язык — реализовать их как библиотеку было никак (не знаю, что-то изменилось с тех пор? было это уже лет 10 если не 15 назад). В общем, выводы делайте сами… :)
Так вот, на что хочу обратить внимание:, когда кому-то понадобились континуации, он просто их взял и сделал сам — без внесений изменений в язык! Причем сделал все это, уйдя с Ruby, так как не смог на тот момент добиться внесения тех самых континуаций в язык — реализовать их как библиотеку было никак (не знаю, что-то изменилось с тех пор? было это уже лет 10 если не 15 назад). В общем, выводы делайте сами… :)
+1
Со Smalltalk, увы, не доводилось работать. Если это настолько мощный язык — почему он не в числе основных, используемых для разработки бизнес-приложений? Просто любопытно.
+2
Он использовался и до сих пор используется в областях, где необходимо в одной системе объединить огромное количество бизнес логики. Причем, наращивание объемов и функциональности системы, на удивление, не приводит к усложнению кода. Грубо говоря, сложность восприятия растет линейно в зависимости от объемов кодовой базы.
В свое время Smalltalk был вытеснен Java и, как многие считают, это вытеснение было целенаправленным и, по сути своей, политическим решением.
Вообще, если интересно, можете посмотреть лекцию на youtube, где Роберт Мартин рассказывает о том, почему Smalltalk ушел со сцены, и предостерегает сообщество Ruby (во многом, идейного наследника Smalltalk) от подобной участи.
В свое время Smalltalk был вытеснен Java и, как многие считают, это вытеснение было целенаправленным и, по сути своей, политическим решением.
Вообще, если интересно, можете посмотреть лекцию на youtube, где Роберт Мартин рассказывает о том, почему Smalltalk ушел со сцены, и предостерегает сообщество Ruby (во многом, идейного наследника Smalltalk) от подобной участи.
+1
… Только, пожалуйста, не воспринимайте то, что дядя Боб там говорит очень всерьез. Он извращает ситуацию в угоду развлекательности и продвижению «своих» «идей» о программировании (первое подчинено второму, разумеется).
Ситуация со Smalltalk довольно сложна, и там всего намешано. Конечно, Smalltalk не идеален, но он менее неидеален, чем современный mainstream. Причина его провала не в этом. Да и о полном и окончательном провале говорить пока что рано — «я так думаю!»). Идеи, заложенные в Smalltalk, пробираются к людям разными путями, иногда очень медленно, и почти всегда сначала в очень перевранном виде. Но находят. Так что, вполне вероятно, мы еще встретимся со Smalltalk либо непосредственно, либо в новом воплощении. … В общем, закругляюсь, ибо оффтопик получается.
Ситуация со Smalltalk довольно сложна, и там всего намешано. Конечно, Smalltalk не идеален, но он менее неидеален, чем современный mainstream. Причина его провала не в этом. Да и о полном и окончательном провале говорить пока что рано — «я так думаю!»). Идеи, заложенные в Smalltalk, пробираются к людям разными путями, иногда очень медленно, и почти всегда сначала в очень перевранном виде. Но находят. Так что, вполне вероятно, мы еще встретимся со Smalltalk либо непосредственно, либо в новом воплощении. … В общем, закругляюсь, ибо оффтопик получается.
0
А можете пояснить, почему конструкцию с await/async называют resumable? Там же ничего не приостанавливается, нет?
А есть какая-то информация на тему того, как будет работать yield? Что будет происходить с контекстом текущего треда?
Как это вообще будет внутри работать?
А есть какая-то информация на тему того, как будет работать yield? Что будет происходить с контекстом текущего треда?
Как это вообще будет внутри работать?
0
Я подозреваю что yield будет работать как в C# но немного иначе, что-то вроде
auto seq = range(0,100);
do
{
int i = seq.next();
// do smth with i
}while(i < 100);
auto seq = range(0,100);
do
{
int i = seq.next();
// do smth with i
}while(i < 100);
0
Дело в том, что C# (как и питон) — управляемый язык. На нативном C++ реализация будет сложнее.
+2
Почему?
Не вижу никаких причин, почему аналогичную конструкцию сложно будет реализовать на неуправляемом языке.
yield
в C# реализуется очень просто: для метода создается класс, в котором есть поля для всех локальных переменных, а также поля StateId и Current. В начало кода метода вставляется блок-диспетчер наподобие следующего:switch(StateId)
{
case 1: goto YIELD_1; break;
case 2: goto YIELD_2; break;
...
}
Не вижу никаких причин, почему аналогичную конструкцию сложно будет реализовать на неуправляемом языке.
+4
Более того, есть же реализации на уровне boost'а.
www.crystalclearsoftware.com/soc/coroutine/coroutine/tutorial.html#coroutine.generators
www.crystalclearsoftware.com/soc/coroutine/coroutine/tutorial.html#coroutine.generators
+1
А что происходит с регистрами? А со стеком?
А я правильно понимаю, что у нас внезапно все переменные вместо стека начинают в куче выделяться?
А я правильно понимаю, что у нас внезапно все переменные вместо стека начинают в куче выделяться?
+2
Не все, а только те, которые в resumable-функции. Это один из вариантов реализации, как писалось в статье, пока не понятно, стоит ли реализовывать этот так, или придумывать что-то еще.
+1
Я бы воспринимал yield скорее как синтаксический сахар.
Представьте, что есть следующий код: (пример на C#, но думаю человеку знакомому с C++ будет достаточно понятно)
Он трансформируется в достаточно длинную портянку:
Все локальные переменные, требуемые между вызовами
Представьте, что есть следующий код: (пример на C#, но думаю человеку знакомому с C++ будет достаточно понятно)
public IEnumerable<int> Enumerate()
{
yield return 1;
yield return 2;
}
Он трансформируется в достаточно длинную портянку:
public IEnumerable<int> Enumerate()
{
return new __InnerClass1();
}
class __InnerClass1 : IEnumerable<int>
{
public int Current { get; private set; }
private int StateId;
public bool MoveNext()
{
switch(StateId)
{
case 0: goto YIELD_1; break;
case 1: goto YIELD_2; break;
default: return false;
}
YIELD_1:
Current = 1;
StateId = 1;
return true;
YIELD_2:
Current = 2;
StateId = 2;
return false;
}
}
Все локальные переменные, требуемые между вызовами
yield
, должны быть реализованы в виде полей класса __InnerClass1
, а соответственно да, скорее всего будут выделяться в куче, а не на стеке. Разумеется, на скорости выполнения это сказывается негативно — уже хотя бы потому, что каждый yield
вызывает переключение контекста. С другой стороны, итераторы экономят память: с их помощью можно описывать бесконечные последовательности значений, или просто писать понятный и читаемый код, не критичный к скорости выполнения.+4
new __InnerClass1
будет создан в куче со всеми вытекающими — нехватка памяти, исключения, необходимость следить за исключениями и прочее.0
Это кстати немного напрягает, что появляются такие неявности запрятанные за обычным кодом. Еще немного непонятно насколько все это действительно будет работать на практике (не пришлось использовать async/await C#), в часности интересно такая вещь: если мы вызываем async функцию внутри своей, свою функцию надо тоже объявить как async (либо заблокироваться и ждать окончания). Получается async «заражает» всю цепочку вызовов наверх.
0
Не обязательно. Компилятор может объявить его как
Опять же, серебряной пули не бывает.
struct
и объявлять в качестве локальной переменной на стеке в том методе, где был вызван итератор, тем самым заинлайнив его. Вариант нехватки памяти на объект такого типа кажется мне примерно настолько же вероятным, как ситуация, когда у вас вдруг переполнится стек при попытке аллоцировать на нем локальную переменную.Опять же, серебряной пули не бывает.
yield
и async-await
не вносят в язык ничего такого, что раньше вообще было невозможно реализовать. Они просто добавляют удобный и легковесный синтаксис, за который, как за любую обертку высокого уровня, придется платить производительностью. Никто не заставляет вас использовать эти возможности в вашем коде, если вы выжимаете из него последние байты и миллисекунды, но появление таких возможностей в языке — это всегда приятно.+1
Наверное потому, что оригинальная функция прекращает свою работу, «подписывая» future на некую лямбду с остальным кодом. Он уже будет вызван другой стороной по мере появления значения и тем самым функция «продолжится».
0
resumable — это ведь не «приостановка», это «возобновление». Работа функции, дёрнувшей через await другую функцию, возобновляется после выполнения этой другой функции.
+1
1. Можно войти в тот же самый стек фрейм (не путать с другим стек фреймом для той же самой функции) даже после выхода из этой функции
2. Точно так же как и __async/__await, собственно yield довольно тривиально пишется если есть __await (но сахар все равно лучше)
3. Возможных реализаций несколько и одна из них — та, что в шарпе — конечный автомат. На build2013 (кажется, хотя может это был и going native) был доклад о реализации __async/__await в VS. Для каждой операции, выполняющейся асинхронно, динамически выделяется отдельный стек фрейм и указатель стека перекидывается между фреймами в прологе/эпилоге функции.
2. Точно так же как и __async/__await, собственно yield довольно тривиально пишется если есть __await (но сахар все равно лучше)
3. Возможных реализаций несколько и одна из них — та, что в шарпе — конечный автомат. На build2013 (кажется, хотя может это был и going native) был доклад о реализации __async/__await в VS. Для каждой операции, выполняющейся асинхронно, динамически выделяется отдельный стек фрейм и указатель стека перекидывается между фреймами в прологе/эпилоге функции.
+1
Почему-то думал, что будет говорится как раз о корутинах и yeld, а последний здесь упомянут, но не в контексте сопроцедур, а на них же тоже можно строить вполне удобную замену колбэкам.
+2
К слову о плюшках в свежих плюсовых компиляторах: недавно попробовал сделать массив из функций с помощью списка инициализации в ICC. Вот результат. Я немного в шоке :)
+2
Интересно, а кого они троллят, вводя в VS 2012 в диалекте C++/CLI такой синтаксис?
C# программисты в шоке, С++ программисты морщатся в отвращении. Смысл, конечно, понятен, но мне жалко тех, кому прийдется такой «С++» код саппортить или даже портировать на другую платформу.
public ref class FooBase abstract : public BarBase {
..
virtual void GetFoo(Platform::WriteOnlyArray<int>^ params);
internal:
void Bar(Platform::Object^ sender) override
{
Window::Current->CoreWindow->SizeChanged +=
ref new TypedEventHandler<CoreWindow^, WindowSizeChangedEventArgs^>(sender, &FooBase::OnWindowSizeChanged);
}
..
};
C# программисты в шоке, С++ программисты морщатся в отвращении. Смысл, конечно, понятен, но мне жалко тех, кому прийдется такой «С++» код саппортить или даже портировать на другую платформу.
+2
И мне жалко. Но вообще весь С++/CLI — это либо чтобы сделать тонкий клиент от С++ кода к дотнету (если из него чего вдруг надо), или тонкая прослойка между основным продуктом на .NET и проверенной библиотекой на С++, которую переписывать нет ни желания ни нужды.
В пределах пары сотен строк с С++/CLI ещё можно жить. Писать на нём целиком большой продукт — это надо быть хорошо двинутым.
В пределах пары сотен строк с С++/CLI ещё можно жить. Писать на нём целиком большой продукт — это надо быть хорошо двинутым.
+6
Это C++/CX. Я только понять не могу чего C++ программисты морщатся? Делегаты сам приводить он не умеет, потому такая страшная строчка в Bar() вышла. В остальном все довольно неплохо.
0
Имхо вполне правильно тащить удачные фичи из одного языка в другой.
В C++ обязательно надо добавить async\await и yield из C#. А в C# надо реализовать шаблоны, как в C++ или хотябы подмножество, как в F#.
А еще в обоих надо TypeClasses как в Цацкелле.
В C++ обязательно надо добавить async\await и yield из C#. А в C# надо реализовать шаблоны, как в C++ или хотябы подмножество, как в F#.
А еще в обоих надо TypeClasses как в Цацкелле.
+1
А в C# надо реализовать шаблоны, как в C++
Странно. Я всегда считал, что в С++ самые ужасные шаблоны.
+1
Они ужасны, но полны по Тьюрингу, поэтому на них можно реализовать хоть чёрта лысого.
+3
По сравнению с чем?
+1
самые ужасные шаблоныОчевидно, по сравнению со всеми остальными языками.
+2
По сравнению с C#, например.
0
В C# нет шаблонов, есть Generic. Шаблоны инстанцируются в compile-time и могут, например, реализовать rank-2 полиморфизм.
А F# есть подобная штука, называется compile-time generics, но она работает только в inline функциях, что сильно ограничивает применение.
А F# есть подобная штука, называется compile-time generics, но она работает только в inline функциях, что сильно ограничивает применение.
+3
Я понимаю, что шаблоны и generics — это не одно и то же. Generics из C# красиво и элегантно вписан в систему типов, а шаблон в C++ — это тупо макрос, который тупо подставляет типы в нужные места, а потом пытается скомпилить.
Я понимаю, что макросы — это тоже хорошо. Местами, они бывают незаменимы. Но я бы предпочел язык с мощной системой типов, языку с мощной системой макросов.
Я понимаю, что макросы — это тоже хорошо. Местами, они бывают незаменимы. Но я бы предпочел язык с мощной системой типов, языку с мощной системой макросов.
+1
А почему нельзя совместить? Что принципиально мешает сделать compile-time generics в C#? Что мешает сделать явные ограничения для шаблонов в C++?
0
Как минимум, generics в C# не поддерживает ни явную, ни частичную специализацию, ни переменное число параметров (variadic generics), а также не позволяет задавать типы в качестве параметров по-уолчанию и определять нешаблонные типы.
0
std::yield реализовать стоит — его реализация в духе недавних добавлений функциональщины. А зачем await? Какая-то нехорошая идея у [Microsoft?] плодить кучу отдельных слов (async хотя бы стоит в определённом месте и его можно не делать зарезервированных в других местах), хотя всё можно прекрасно запихнуть в методы std::futures.
И я так и не понял, зачем нужны асинхронные не системные вызовы? Они ж всё равно не смогут выполняться в то же время (а неявный вызов других потоков — это слишком высокоуровнево для включения в C++).
И я так и не понял, зачем нужны асинхронные не системные вызовы? Они ж всё равно не смогут выполняться в то же время (а неявный вызов других потоков — это слишком высокоуровнево для включения в C++).
0
Кстати вопрос знатокам.
Если я правильно понимаю, то работать async\await будет ровно как в C# — переписывать функции в КА, а замыкания в классы. Как при этом будет сделан контроль времени жизни\владения? Где будет храниться объект-замыкание?
Если я правильно понимаю, то работать async\await будет ровно как в C# — переписывать функции в КА, а замыкания в классы. Как при этом будет сделан контроль времени жизни\владения? Где будет храниться объект-замыкание?
0
Это какой-то не С++-способ, оверхеда много. Скорее сделают выделение области данных в куче, туда поскладывают всё нужное, а контроль времени жизни этой области сделают каким-нибудь счетчиком ссылок на неё из всех замыканий. Но это так, фантазии. Посмотрим, как оно будет.
0
И что там с исключениями?
Ты, кстати, проходишь курс Мартина Одерского и Эрика Мейера «Principles of Reactive Programming» на курсере? В Scala те же async/await.
Ты, кстати, проходишь курс Мартина Одерского и Эрика Мейера «Principles of Reactive Programming» на курсере? В Scala те же async/await.
+1
Об этой теме неплохо рассказали на GoingNative
channel9.msdn.com/Events/GoingNative/2013/Bringing-await-to-Cpp
Из доклада становится ясно, что Microsoft включи эту фичу в компилятор по своим собственным соображениям, скорее всего ради пользователей WinRT.
Вообще какая-то странная статья.
Крайне сомнительное использование then. Зачем он, если результата мы уже синхронно дождались строчкой выше?
ССЗБ, стандарт резервирует такие имена.
channel9.msdn.com/Events/GoingNative/2013/Bringing-await-to-Cpp
Из доклада становится ясно, что Microsoft включи эту фичу в компилятор по своим собственным соображениям, скорее всего ради пользователей WinRT.
Вообще какая-то странная статья.
std::future<int> f_int = make_dummy_future(42); int i = f_int.get() // ждём окончания работы функции f_int.then([](std::future<int> i){/* deal with it */})
Крайне сомнительное использование then. Зачем он, если результата мы уже синхронно дождались строчкой выше?
а вдруг у вас были переменные с именами __async\__await ?
ССЗБ, стандарт резервирует такие имена.
0
>Зачем он, если результата мы уже синхронно дождались строчкой выше?
Это два несвязанных друг с другом примера использования. Я согласен, что немного нелогично выглядит, но так в оригинале, а это всего лишь перевод.
>ССЗБ, стандарт резервирует такие имена.
Вон в предложении уже решили __async в resumable переименовать. Риск некоторый есть.
Это два несвязанных друг с другом примера использования. Я согласен, что немного нелогично выглядит, но так в оригинале, а это всего лишь перевод.
>ССЗБ, стандарт резервирует такие имена.
Вон в предложении уже решили __async в resumable переименовать. Риск некоторый есть.
0
решили __async в resumable переименовать
Я где-то слышал (кажется, в Design and Evolution of C++), что новые ключевые слова, добавляемые в язык, выбираются странноватыми как раз для уменьшения вероятности коллизий. typename, к примеру странное слово, и обычный программист врядли решит так назвать класс или перменную. Думаю, с resumable аналогичная ситуация. Мне бы такое слово в голову само не пришло.
0
В предложении __async не было, было async.
Для правильного кода риска нет — по стандарту все имена, начинающиеся с двух подчеркиваний, зарезервированы для реализации языка (в т.ч. для языковых расширений). Именно отсюда все эти __async и __attribute__.
Для правильного кода риска нет — по стандарту все имена, начинающиеся с двух подчеркиваний, зарезервированы для реализации языка (в т.ч. для языковых расширений). Именно отсюда все эти __async и __attribute__.
0
А потом комиссия по языку составит свой вариант данного решения и будет два несовместимых варианта реализации: MSVC и все остальные. Что-то мне это напоминает.
0
В оригинальной статье многое, увы, напутано. Причем это ровно те же грабли, на которые люди массово наступали, осваивая async/await в C#.
>> Внутри resumable функции вещи происходят тоже слегка иначе. Используя ключевое слово await теперь можно «завернуть» выражение или вызов функции в future, которая посчитает это выражение или вызов в другом потоке.
await ничего никуда не заворачивает — наоборот, она «разворачивает» значение типа std::future (возможно, но не обязательно, возвращенное из другой resumable функции), асинхронно ожидая завершения вычисления и вытаскивая полученное значение (или исключение).
Чтобы завернуть вызов обычной синхронной функции в future, нужно использовать std::async. Что, кстати, наглядно видно из приведенного там же примера кода.
>> И вот мы подоходим к интересному. Вы можете использовать ключевое слово await неоднократно — каждое его применение создаст std::future, которая начнёт выполняться в параллельном потоке.
Те же грабли, вид сбоку. Еще раз — await не создает экземпляры std::future, а получает значения из них.
Ну и о «параллельных потоках» — это тоже неправда. Далеко не каждый future выполняется на своем потоке. Например, вполне возможна реализация всяческой асинхронщины в reactor style, вообще на одном потоке (как в node.js) с циклом сообщений/коллбэков. Туда же всяческие completion ports и прочие средства асинхронного I/O.
Единственный случай, когда future гарантированно выполняется на своем потоке — это когда синхронный код обернут через std::async. Во всех остальных случаях, это деталь реализации данного конкретного future.
>> Внутри resumable функции вещи происходят тоже слегка иначе. Используя ключевое слово await теперь можно «завернуть» выражение или вызов функции в future, которая посчитает это выражение или вызов в другом потоке.
await ничего никуда не заворачивает — наоборот, она «разворачивает» значение типа std::future (возможно, но не обязательно, возвращенное из другой resumable функции), асинхронно ожидая завершения вычисления и вытаскивая полученное значение (или исключение).
Чтобы завернуть вызов обычной синхронной функции в future, нужно использовать std::async. Что, кстати, наглядно видно из приведенного там же примера кода.
>> И вот мы подоходим к интересному. Вы можете использовать ключевое слово await неоднократно — каждое его применение создаст std::future, которая начнёт выполняться в параллельном потоке.
Те же грабли, вид сбоку. Еще раз — await не создает экземпляры std::future, а получает значения из них.
Ну и о «параллельных потоках» — это тоже неправда. Далеко не каждый future выполняется на своем потоке. Например, вполне возможна реализация всяческой асинхронщины в reactor style, вообще на одном потоке (как в node.js) с циклом сообщений/коллбэков. Туда же всяческие completion ports и прочие средства асинхронного I/O.
Единственный случай, когда future гарантированно выполняется на своем потоке — это когда синхронный код обернут через std::async. Во всех остальных случаях, это деталь реализации данного конкретного future.
+2
На rsdn критикуют: rsdn.ru/forum/cpp/5366756.1 и rsdn.ru/forum/cpp/5366761.1
весьма любопытно почитать — получается, что данное решение собирает недостатки stackless и stackfull coroutines.
весьма любопытно почитать — получается, что данное решение собирает недостатки stackless и stackfull coroutines.
+2
Небольшое замечание про «обновление компилятора — нетривиальное событие»
Вообще-то был «November 2012 CTP», (ну правда он был доступен уже в октябре ;-) )
В нем впервые появились многие фичи C++ 11.
Вообще-то был «November 2012 CTP», (ну правда он был доступен уже в октябре ;-) )
В нем впервые появились многие фичи C++ 11.
0
Sign up to leave a comment.
Resumable функции