Здравствуйте, alex_public, Вы писали:
_>Все правильно. Только вот ты перечислил исключительно отрицательные стороны большой истории языка. А есть и положительные: огромное число уже готовых программистов, инструментов, библиотек. Так вот, если народ будет полностью уверен, что пути C++ и Rust где-то в будущем пересекутся (в том смысле что C++ заберёт к себе все ключевые вкусности Rust'a), то у них не будет вообще никакого стимула слезать с текущих перечисленных выше вкусностей C++. Т.е. как C++11 по сути поставил крест (причём это произошло ещё до выхода самого стандарта, на этапе обсуждения и тестовых релизов в компиляторах) на выход D в мейнстрим (а одно время было ощущение, что ведущие спецы по C++ утомились попытками выжать невозможное из устаревшего языка и готовы перейти на D, где есть всё что надо), так и C++17 может поставить крест (опять же прямо сейчас, а не после 17-го года) на выход Rust'а в мейнстрим. Ведь думаю ни для кого не секрет, что такие языки как D, Rust, Nim и т.п., имеют шанс на выход в мейнстрим исключительно путём перехвата аудитории C/C++? И если C++ не будет давать им такого шанса (быстрым развитием в нужном направление), то...
Отчасти согласен, хотя есть с чем не согласиться. У C++ много готовых программистов, хотя уровень их, в общем случае, оставляет желать лучшего. C++11 вернул надежду в то, что язык будет полезен, хотя C++17 уже начинает пугать своей монструозностью и перегруженностью. Не забывай о том, что Rust дает много плюшек и одна, ключевая на мой взгляд – простота языка. C++17 – это ж просто монстр какой-то сверхперегруженный, и что еще хуже, ты не можешь пользоваться только им, знать C++03 (а иногда и C++98) так же необходимо.
Тот же Go довольно успешно отобрал изрядный кусок рынка у C++, тоже делает и Rust, который в отличие от Go может подвинуть не только C++, но и C благодаря тому, что может работать вообще без рантайма. Мало кто любит писать на слишком уж перегруженных языках и уметь ориентироваться в как минимум 3-х стандартах (по 1200+ страниц каждый). Так что C++17, как мне кажется, это скорее не убийца D/Rust/Nim (хотя что убивать и так дохлый D и почти никому не известный Nim?), а гвоздь в гроб C++ – нельзя делать таких монстров, задалбывает их учить
Здравствуйте, red75, Вы писали:
R>>>Я где-то тут приводил темплейтно/макросный ужас, который нужен для более-вменяемого discriminated union. EP>>Готовый Boost.Variant есть уже больше 13 лет — бери и используй. Если хочется реализовать свой, то на C++14 он реализуется на порядки проще чем на C++98. R>Отсутствие прямой поддержки языком сложно компенсировать. Нормальный pattern-matching c case totality check библиотекой не сделаешь.
Это выделение есть только в определённых случаях. При этом даже если бы Variant был встроен в язык — то этот tradeoff всё равно пришлось бы так или иначе совершать
R>Небольшая библиотечка, которая работает начиная с gcc 4.7, то есть 4 года, позволяющая более-менее комфортно извлекать значения из variant https://github.com/exclipy/inline_variant_visitor
Ну да, с появлением лямбд inline-обход спокойно реализуется, например
vector<variant<int, double>> ys;
for(auto x : xs)
ys.push_back
(
MATCH(x)
CASE(x IS widget) { println("x IS widget"); return 1; }
CASE(x IS gadget) { println("x IS gadget"); return 0.1; }
);
R>то есть 4 года
То есть пока Rust пешком под стол ходил, в реальных проектах C++ можно было не только использовать Variant, но и комфортно его обходить, с гарантией обратной совместимости. При этом в mainstream языках помимо C++ ничего подобного нет и по сей день.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Что насчёт проверки границ? Крайне распространённый случай.
Само собой есть. Выглядит как-то так:
fn main() {
let v = vec![1, 2, 3];
let t = v[3];
}
thread '<main>' panicked at 'index out of bounds: the len is 3 but the index is 3', ../src/libcollections/vec.rs:1137
С одной стороны, никакого непредвиденного поведения с отложенным падением, с другой, на этапе компиляции такие ошибки не отслеживаются (можно ли такое отследить во время компиляции отдельный вопрос). Само собой, можно повторить типичный C/C++ выход за границы с непредсказуемым падением воспользовавшись unsafe.
Здравствуйте, kaa.python, Вы писали:
KP>Само собой, можно повторить типичный C/C++ выход за границы с непредсказуемым падением воспользовавшись unsafe.
, либо мы платим тормозами за корректность, либо заворачиваемся в unsafe даже в таких типичных местах как массивы.
Тот, кому важны микросекунды – C++ тоже не возьмет по причине слишком больших накладных расходов в виде обработки исключений, подсчете ссылок и т.д. Посмотри на тесты скорости: в 50% случаев Rust обгоняет C++, в 30% обгоняет C и это без unsafe. Именно поэтому я и говорю о том, что Rust вобщем-то не уступает C++ и лишь слегка проигрывает C в скорости работы сгенерированного кода. Но при этом, он дает ряд гарантий о которых в C никто даже не мечтает, а в C++ изредка задумываются и рождают очередного монстра.
Здравствуйте, kaa.python, Вы писали:
KP>Тот, кому важны микросекунды – C++ тоже не возьмет
И что же он возьмёт?
KP>по причине слишком больших накладных расходов в виде обработки исключений,
На x64 практически zero-overhead exceptions на happy-path. Там где это играет значимую роль — их можно не использовать или даже отключить.
KP>подсчете ссылок и т.д.
Подсчёт ссылок требуется крайне редко — там где требуется разделяемое владение и точка удаления зависит от внешних условий. В Rust кстати, как я вижу, в этих же местах будет тот же самый подсчёт ссылок
KP>Посмотри на тесты скорости: в 50% случаев Rust обгоняет C++,
Подозрительные тесты, например нет -DNDEBUG. В общем нужно проверять.
KP>в 30% обгоняет C и это без unsafe.
C в среднем тот ещё тормоз, на него не надо ровняться. Отсутствие шаблонов закономерно ведёт к избыточному стиранию типов и аллокациям, каноничный пример — GLib.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, red75, Вы писали:
R>>>>Я где-то тут приводил темплейтно/макросный ужас, который нужен для более-вменяемого discriminated union. EP>>>Готовый Boost.Variant есть уже больше 13 лет — бери и используй. Если хочется реализовать свой, то на C++14 он реализуется на порядки проще чем на C++98. R>>Отсутствие прямой поддержки языком сложно компенсировать. Нормальный pattern-matching c case totality check библиотекой не сделаешь.
EP>Сделаешь. Pattern-matching по типам (то что нужно для Variant) есть в C++ начиная с C++98, totality check автоматом вытекает из свойств перегрузки. EP>Лямбды для inplace-ности появились в C++11, да
Под нормальным паттерн-матчингом я имел в виду в том числе и destructuring. Вот, только что написал:
for (idx, vref) in chunk.iter_mut().enumerate() {
...
};
Это получение индексов и ссылок на мутабельные элементы массива без проверок границ массива. (idx, vref) деструктурирует tuple, возвращаемый enumerate().
Какое-то подобие деструктурирования tuple в C++ есть: std::tie() lvalue с использованием временных переменых, но более сложные случаи, вроде нижеприведенного, уже не обработаешь.
match maybe_point {
Some(x,y) => {...},
None => {...},
}
EDIT: Вставлю полный код. Параллельная обработка массива в несколько потоков:
crossbeam::scope(|scope| {
let chunk_len = (cubes.len()/thread_cnt as usize)+1;
for (ch_idx, chunk) in cubes[..].chunks_mut(chunk_len).enumerate() {
let start = ch_idx*chunk_len;
scope.spawn(move || {
for (idx, c) in chunk.iter_mut().enumerate() {
let cube = &self.cubes[start+idx];
*c = CubeState {
pos: cube.pos + cube.spd * dt,
rot: Basis3::from_axis_angle(cube.rot_axe, Angle::from(deg(cube.rot_spd * dt))).concat(&cube.rot),
.. *cube
};
};
});
};
});
EDIT2: Можно вообще без проверок границ массива в self.cubes[start+idx] обойтись:
crossbeam::scope(|scope| {
let chunk_len = (cubes.len()/thread_cnt as usize)+1;
for (chunk, chunk_src) in cubes[..].chunks_mut(chunk_len).zip(self.cubes[..].chunks(chunk_len)) {
scope.spawn(move || {
for (c, cube) in chunk.iter_mut().zip(chunk_src) {
*c = CubeState {
pos: cube.pos + cube.spd * dt,
rot: Basis3::from_axis_angle(cube.rot_axe, Angle::from(deg(cube.rot_spd * dt))).concat(&cube.rot),
.. *cube
};
};
});
};
});
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>И что же он возьмёт?
Си?
EP>На x64 практически zero-overhead exceptions на happy-path. Там где это играет значимую роль — их можно не использовать или даже отключить.
Ну начинается, отключить один из основополагающих механизмов языка...
EP>Подсчёт ссылок требуется крайне редко — там где требуется разделяемое владение и точка удаления зависит от внешних условий. В Rust кстати, как я вижу, в этих же местах будет тот же самый подсчёт ссылок
std::shared_ptr?
EP>Подозрительные тесты, например нет -DNDEBUG. В общем нужно проверять.
Хорошие тесты, уже лет 10 как единственный сравнительно объективный способ узнать скорость выполнения кода на том или ином языке.
EP>C в среднем тот ещё тормоз, на него не надо ровняться. Отсутствие шаблонов закономерно ведёт к избыточному стиранию типов и аллокациям, каноничный пример — GLib.
Я могу сказать только одно. Можно и дальше "молиться" на C++ и надеяться что "вот уж со следующим стандартом жизнь наладится", а можно просто посмотреть по сторонам. C++ слишком тяжел, сложен и обладает очень громоздким наследием. Его не просто так теснят все кому не попадя, начиная от JMV-языков, заканчивая Go. Если есть два варианта решения одной и той же задачи с одним и тем же уровнем эффективности, никто, кроме как из "религиозных" соображений, не возьмет более сложный инструмент.
Здравствуйте, kaa.python, Вы писали:
EP>>И что же он возьмёт? KP>Си?
Зачем?
EP>>C в среднем тот ещё тормоз, на него не надо ровняться. Отсутствие шаблонов закономерно ведёт к избыточному стиранию типов и аллокациям, каноничный пример — GLib. KP>Я могу сказать только одно. Можно и дальше "молиться" на C++ и надеяться что "вот уж со следующим стандартом жизнь наладится",
Так было до C++11 — так как был огромный промежуток между стандартами. Move semantic, variadic templates, auto, замыкания — всё это действительно ждали а-ля "жизнь наладится".
В C++11 было несколько белых пятен, которых не хватало для целостности, типа полиморфных лямбд, auto return type и т.д. C++14 закрыл эти дыры.
В C++17 ничего прорывного не планируется, разве что concept lite. И сейчас нет никакого ощущения а-ля "вот уж со следующим стандартом жизнь наладится"
KP>а можно просто посмотреть по сторонам. C++ слишком тяжел, сложен и обладает очень громоздким наследием. Его не просто так теснят все кому не попадя, начиная от JMV-языков, заканчивая Go. Если есть два варианта решения одной и той же задачи с одним и тем же уровнем эффективности, никто, кроме как из "религиозных" соображений, не возьмет более сложный инструмент.
Согласен, C++ слишком тяжёл и обладает громоздким наследием. Можно оставаться в рамках удобного и современного subset, но действительно, скорей всего рано или поздно придётся столкнутся со старым кодом, или просто старым стилем, и для его понимания и модификации придётся освоить всю эту тяжесть.
Но полностью заменить C++ сможет язык у которого точно такие же design guidelines, те же самые принципы. Если же guidelines отличаются, то максимум что получиться — это откусить какую-то часть рынка, точно также как в своё время откусили Java и C#.
Я был бы только рад если бы была полноценная современная замена C++ без всей этой тяжести и громоздкого наследия, но увы её на данный момент нет. Насколько я вижу — ближе всех подошёл D, но даже сами авторы заявляют что D следует другим принципам.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Согласен, C++ слишком тяжёл и обладает громоздким наследием. Можно оставаться в рамках удобного и современного subset, но действительно, скорей всего рано или поздно придётся столкнутся со старым кодом, или просто старым стилем, и для его понимания и модификации придётся освоить всю эту тяжесть.
Нельзя оставаться в рамках современного подмножества. Новички в C++ идут крайне не охотно (и правильно делают), те кто выучил его давно очень часто не учат никакого нового подмножества. При этом язык разрешает творить что угодно, и очень часто, это что угодно выглядит как жутчавшее УГ. Проблема C++ в том, что для его корректного использования нужна очень продвинутая команда, т.к. компилятор по рукам дает крайне редко.
EP>Но полностью заменить C++ сможет язык у которого точно такие же design guidelines, те же самые принципы. Если же guidelines отличаются, то максимум что получиться — это откусить какую-то часть рынка, точно также как в своё время откусили Java и C#.
Да никто его полностью не заменит, нужно же кучу копролита мамонта поддерживать, дорабатывать, развивать.
Здравствуйте, uncommon, Вы писали:
EP>>В C++17 ничего прорывного не планируется, разве что concept lite. U>Да ну? Прямо из Бьярновского отчёта: U>
U>Summary of the features (discussed in this meeting) that I consider most significant:
U>Concepts
U>Modules
U>Parallelism TS
U>Ranges TS
U>Concurrency TS
U>Contracts
U>Coroutines
U>Order of evaluation
U>Uniform function call syntax
U>variant, array_view, and string_view
U>Structured bindings (simpler handling of multiple return values)
U>[fallthrough]]
U>Как ни крути, штук 5 больших прорывных фич будет.
Модули под большим вопросом, то есть их может и не быть в C++17. Из более менее прорывного — концепции, их давно ждут.
Что здесь ещё принципиально прорывного? Что ждут вот так чтобы прям "жизнь наладилась"?
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Подозреваю что как раз в общем случае оно и верно. EP>Каким образом? Если у нас язык полный по Тьюрингу, то в статике такая задача неразрешима.
Да, в _самом_ общем случае, конечно, неверно.
Я имел в виду, что можно свести все множество корректных программ к подмножеству, правильность которого можно доказать статически. (Конечно, наверняка некоторая часть корректных программ по каким-то причинам — время доказательства, например — не может быть сведена к этому подмножеству, и придется вводить "небезопасные недоказанные блоки".)
Rust на данный момент такой цели перед собой не ставит, у него задачи менее амбициозные и более приближенные к реальности.
DM>-Ножами жонглировать трудно и опасно! DM>-Не опасно и легко, надо просто правильно это делать. DM>-Трудно и опасно, я пробовал и весь поранился. DM>-Ты просто не можешь в жонглирование и жалуешься на жизнь.
Скорее так:
— Пить алкоголь опасно.
— Не опасно если меру знать.
— Нет, каждый раз, когда я пробую алкоголь, оказываюсь в вытрезвителе и однажды лишился бумажника.
— ??!!%$#
R>1) Статические анализаторы в комплекте с С++ не идут. В стандарте не написано: "Вы должны использовать статический анализатор, чтобы не использовать одну из многих любезно предоставленных нами возможностей выстрелить себе в ногу".
По крайней мере они там есть. В ногу можно выстрелить везде. В том же Rust строки — мутабельные. Язык, появившийся в 2015-м году имеет мутабельные строки в своей стандартной библиотеке. Жизнь людей ничему не учит.
R>2) Крупные компании прекрасно понимают, что идеальных программистов, помнящих и мгновенно замечающих все неопределенные и неспецифицированные поведения, и с первого взгляда выполняющих
двухфазное разрешение имён, с учетом всего исходника проекта, не существует. Поэтому пытаются ужать всю мощь и свободу С++ до приемлемых рамок: https://google.github.io/styleguide/cppguide.html
Это ты еще не видел style guide блумберга. Style guide нужен не для того, чтобы ограничить мощь до приемлемых рамок а для того, чтобы унифицировать код. Чтобы сделать чтение и переиспользование кода более простыми процессами. Для java тоже пишут style guides, даже для питона пишут. Это не аргумент.
R>3) Но это не особо помогает: https://bugs.chromium.org/p/nativeclient/issues/detail?id=245 см. Type 3 Functions, всё равно напоролись на неспецифицированное поведение.
Т.е. в С++ проекте, который содержит десятки миллионов LOC, который пилится огромным количеством людей, нашли баг. Удивительно Баг, кстати, не очень то С++ специфичен.
R>4) Не помню чьё высказвание "Наговнокодить можно на любом языке", которое Вы, вероятно, поддерживаете, совершенно бесполезно для сравнения языков. Вопрос в том насколько легко язык позволяет сделать ошибку обычному программисту. Напомню, что даже Бьярн Страуструп в своей книге по С++ напоролся на неспецифицированное поведение. http://stackoverflow.com/questions/27158812/does-this-code-from-the-c-programming-language-4th-edition-section-36-3-6-ha
Есть две категории языков программирования. Первая категория — языки, которые пытаются сделать так, чтобы программисту было сложно допустить ошибку. Вторая категория — языки на которых максимально просто писать, но которые при этом оставляют возможность выстрелить себе в ногу (хорошие примеры — python, C). С++ это скорее компромисс, его свойства зависят от стиля. На С++ можно нарулить такой интерфейс, который просто не позволит использовать себя неправильно, проверяя корректность в compile time. Но можно писать в стиле Си с классами, тут кто как хочет, так и прелюбодействует.
R>5) 5 простых спобов выстрелить себе в ногу с использованием shared_ptr: http://habrahabr.ru/post/191018/
Бредовая статья.
R>6) Даже комитет по C++ понимает наличие проблем. Планируют введение статического анализа времени жизни переменных, в частности для предотвращения работы с инвалидированными итераторами.
Если это делают в Rust, то это хорошо, если же подобное появляется в С++, то плохо. Ясно-понятно.
R>Итого: С++ медленно ползёт в сторону Rust, таща за собой сорокалетние напластования фич, кучу неопределенных и неспецифицированных поведений в невинно выглядящих конструкциях, тонны legacy-кода.
Да не ползет он никуда.
R>Tooling, конечно, у с++ лучше. Даже gbd уже года 3 показывает правильные значения переменных http://stackoverflow.com/questions/10315430/gdb-prints-wrong-values
Ну gdb он какбы универсален (не только для С++), к тому же мне он показывает правильные значения переменных последние лет эдак 7.
R>А то что я писал про свою программку на Rust это не wishful thinking, а простое следствие того, что статический анализатор встроен в Rust.
Это не статический анализатор.
R>Если выразить инварианты программы на уровне типов, то успешность компиляции будет гарантировать успешность работы. Я, конечно, до такого уровня не дошёл (собственно в Rust'е это полностью и не получится. Например, там нельзя реализовать session types), но по крайней мере могу быть достаточно уверен, что ошибка не вызвана buffer overrun в какой-нибудь отдалённой части программы или кривой библиотеке.
Расскажи нам, пожалуйста, как можно buffer overrun типами запретить. Более или менее сложный код требует проверок в рантайме, хотя бы старый добрый assert. Проверки в CT в С++ нужны в основном в обобщенном коде.
Основная проблема С++ на данный момент — отсутствие системы модулей. Вот это вот все, о чем ты говоришь, это не проблема вообще, люди десятилетиями делают проекты на С++ и даже на С. Есть вещи, которые в С++ делаются намного проще чем в "более мощных" языках программирования. Если мне нужно сделать огромную разреженную таблицу в памяти я буду работать с памятью напрямую (calloc, copy on write, арифметика указателей и все такое) а не возиться с временами жизни в Rust. А если я возьму для этого Rust, мне все равно придется писать unsafe код, только у меня не будет calloc и арифметики указателей и всего такого.
KP>В общем случае – да. В то же время, Rust дает тебе возможность получить такую гарантию в условных 90% случаев, в отличие от C++, который не дает такой гарантии никогда. Думаю, выбор довольно очевиден
Я правильно понял, что если Rust дает такие гарантии, то С++ автоматически перестает давать вообще любые гарантии корректности? Мне кажется что lifetime analysis в Rust очень специфичен. Он позволяет например взять внутренний буфер строки и перелопатить его и не бояться что этот буфер переживет строку. Но этот (и аналогичные ему) кейсы, они же странные. Любой С++ программист это все в голове умеет анализировать. Это все просто.
Здравствуйте, ELazin, Вы писали:
R>>EDIT: Вставлю полный код. Параллельная обработка массива в несколько потоков:
EL>О да! Параллельный код, который вручную создает потоки и вручную делит массив на thread_cnt частей. So solid, so 2016
Я параллельное программирование в контексте С++ вообще не упоминал. Понятно почему? Потому что там с этим полная Ж с большой буквы. Ваша позиция понятна: "Настоящий программист напишет что угодно на чём угодно. И я знаю этого программиста". Особо спорить не о чем.
Здравствуйте, red75, Вы писали:
R>Отсутствие прямой поддержки языком сложно компенсировать. Нормальный pattern-matching c case totality check библиотекой не сделаешь. А так можно, конечно, и гланды ректально вырезать.
Важен же не только синтаксический сахар, но и итоговое быстродействие. К примеру вот у таких https://github.com/solodon4/Mach7 решений сразу видно что с быстродействием...
Здравствуйте, kaa.python, Вы писали:
KP>Не забывай о том, что Rust дает много плюшек и одна, ключевая на мой взгляд – простота языка.
Очень сомнительно. Одни модели памяти уже автоматом делают его мягко говоря не простым. Вот тот же Go — действительно простой. Но у него совсем другая целевая аудитория.
KP>C++17 – это ж просто монстр какой-то сверхперегруженный, и что еще хуже, ты не можешь пользоваться только им, знать C++03 (а иногда и C++98) так же необходимо.
Пока что это всё "пугалки" (ну а для кого-го надежды ), посмотрим что там будет в итоге.
KP>Тот же Go довольно успешно отобрал изрядный кусок рынка у C++, тоже делает и Rust, который в отличие от Go может подвинуть не только C++, но и C благодаря тому, что может работать вообще без рантайма.
Не, Go вообще из другой области. Он скорее где-то между Python/Ruby с одной стороны и Java/C# с другой, отъедая у обоих этих лагерей понемногу. Причём только в одной специфической области веб-бэкенда. В этой области C++ конечно же тоже присутствует но только в особых случаях, требующих повышенного быстродействия (типа поисковиков google, yandex и т.п.), а это Go уже не может. Так что даже в своей родной области Go не может подвинуть C++. Куда уж тут говорить про такие родные области C++ как системный код и т.п.
KP>Так что C++17, как мне кажется, это скорее не убийца D/Rust/Nim (хотя что убивать и так дохлый D и почти никому не известный Nim?), а гвоздь в гроб C++ – нельзя делать таких монстров, задалбывает их учить
Не, это как раз D/Rust/Nim изначально создавались как убийцы C/C++, но что-то они похоже какие-то неудачники пока... )