-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
C++. Глава 4. экскурсия по C++ #163
base: main
Are you sure you want to change the base?
Conversation
Давй добавим про вычисления в компайл-тайме? |
constexpr, consteval, шаблоны, X-макрос ?) Что-то конкретное или про все?) |
constexpr, consteval, constinit. Что из этого и зачем юзается в связке с шаблонами. |
cpp/cpp_chapter_0040/text.md
Outdated
# условия | ||
Для управления потоком исполнения кода есть 3 варианта: `if`, тернарный оператор `?` и `switch`. Начнем с чисел, для примера. | ||
## if ... else if ... else ... | ||
Простой способ проверить а точно ли все у нас в порядке, использовать `if`: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Это одна из первых глав, и читатель еще не освоился с языком. Предлагаю формулировать определения и ценные мысли максимально четко. Что значит, "все ли в порядке"? Что такое if
- это оператор, выражение, что-то еще?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Есть же 3 глава "Базовые концепции". Если конечно их как-то по другому сформировать, то да. Но я следовал от идеи "спирали" и наличия 3 главы, где как я понял, должно быть что-то про выражения и так далее.
И курс все же для абсолютных новичков? Я ориентировался на частично состоявшихся программистов и старался излагать в формате "а в C++ ифчик делается вот так, а не как в вашем питоне/java/c#".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Держим в голове, что в C++ можно попасть из совершенно разных языков. Можно и явы, которая синтаксически во многом похожа. Тогда читателю заранее все понятно. А можно из питона. Тут возникает шок от обилия скобок и точек с запятой. А если человек пришел из раста, мы должы составить текст так, чтоы он четко понял: if - это не выражение. if - это оператор.
Так вот. Глава "базовые концепции" развешивает ружья: объясняет, для чего точки с запятой и скобки разных видов. Что такое оператор, выражение, инструкция. Как одно соотносится с другим. В той главе могут появиться примеры каких-то конструкций из главы "экскурсия". Но лишь каких-то.
А в главе экскурсия ты окончательно расставляешь по полочкам конкретные языковые конструкции. Ты говоришь: if - это оператор. И выглядит он вот так.
И да, курс не для полных новичков. Курс для разработчиков. Поэтому мы не объясняем, что такое условия вообще. И чем полезны циклы. Все это и так знают. Но суть этих базовых конструкций может отличаться в разных языках.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if - это не выражение. if - это оператор.
Выражение, пруф - cpprefence: if statement. Хотя мне тоже хочется сказать "оператор if
".
Могу перефразировать попробовать, Сделать не настолько фамильярным. Тут как раз на контрасте
"Для управления потоком исполнения кода" и "все ли в порядке".
Попробую притянуть к первому варианту.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Нет. Не путай statement и expression. В расте, @khva , поправь, если вру, if - это именно expression. Как и цикл. И это очень важно, потому что в таком случае ты можешь присвоить какой-то переменной результат ифа и результат цикла:
let big_n =
if n < 10 && n > -10 {
println!(", and is a small number, increase ten-fold");
10 * n
} else {
println!(", and is a big number, halve the number");
n / 2
};
Если говорить про тонкости перевода, то есть operator (ну это точно "оператор"), expression (выражение) и statement. Вот statement я бы перевела как инструкция. Это всё, что заканчивается точкой с запятой или является управляющей конструкцией (иф, цикл, ...).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Выражение - это то что у ифа в круглых скобках) Но, повторюсь, сам иф выражением не является.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Нет. Не путай statement и expression. В расте, @khva , поправь, если вру, if - это именно expression. Как и цикл.
Всё верно.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Выражение - это то что у ифа в круглых скобках) Но, повторюсь, сам иф выражением не является.
Понял, дело в переводе. Я так понимаю, мы согласны, в том что if
- statement
, а не expression
или operator
.
Признаю косяк, оперирую понятием "выражение" кажется и для statement
и для expression
. Просто думаю я в англ терминах, а на русский транспалится уже в автомате с пометкой native. )
Вот statement я бы перевела как инструкция.
добро =) будет инструкцией.
```cpp {.example_for_playground ci-wrap=function} | ||
// там где должно быть условие, мы можем сначала инициализировать переменную, | ||
// чтобы ее видимость ну уходила дальше тела if | ||
const int charsInThisChapter = 4000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Предлагаю сразу на старте договориться о стиле кодирования: snake_case, camelCase, расстановке скобок и т.п. Чтобы примеры и задачи во всех главах выглядели единообразно.
@Microvenator какой стиль кодирования планируется использовать в курсе?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Давайте за основу возьмем гугловый как самый распространенный.
https://google.github.io/styleguide/cppguide.html
Тогда, кажется, у @Intey все в целом правильно, а я в своей главе поправлю стиль.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, code should target C++20, i.e., should not use C++23 features.
Ну, наверно только стили, верно? )
Как участник многих holy war по code style, скажу - тут либо линтер в автомате (pre-commit, или уже CI-сборщик), либо оно так и останется только тут. Ну или кто-то будет ходить и на каждую скобку оставлять коммент. Берегите силы! Оно того не стоит)
Насчет линтера могу помочь, уже наработка есть.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Речь не про несамодостаточный код, а код являющийся частью изложения. То есть код, который всегда будут читать и гораздо реже исполнять. И у курса потенциально сильно больше читателей, чем у кода среднестатического проекта. Поэтому важно, чтобы код во всех главах выглядел единообразно.
Есть линтеры, которые могут корректировать код прямо в рамка md-файла?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Есть линтеры, которые могут корректировать код прямо в рамка md-файла?
Его не сложно приготовить. Я написал небольшой скрипт который так же парсит md, выдергивает блоки кода и, пока что, просто прогоняет их через компилятор. Добавить вызов clang-format
- тривиально.
if (const int magic=42; charsInThisChapter == magic) { | ||
std::println("University, it that you?"); | ||
} | ||
else if (charsInThisChapter == 4000) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Здесь и в других условиях используются только операторы сравнения ==
и !=
. Предлагаю упомянуть какие они бывают и разнообразить условия. Например:
if (charsInThisChapter < 2000) {
std::println("too small");
} else if (charsInThisChapter > 4000) {
std::println("too big");
} else {
std::println("well, that was expected!");
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Сделаем!
cpp/cpp_chapter_0040/text.md
Outdated
if (charsInThisChapter != 4000) std::println("Huston, we have a problem"); | ||
``` | ||
|
||
{.task_text } Вам же, предлагаю посчитать ворон. Представим, что вороны могут образовывать "табуны" (табуны это про коней, но допустим) по 2, 5, 10, 89 и 1000 штук. Напишите код, который напечатает для каждого из вариантов: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Вороны могут образовывать стаи. Табун типа для шутки, но не все поймут эту шутку.
- В HOMM названия few, several, pack и тд обозначают диапазоны. Здесь почему-то конкретные числа. Не логично.
- Всего в задаче 5 диапазонов (хорошо не всё 9), но всё равно не прикольно писать 5 веток if-else.
Сорри, задача в текущем виде не очень хороша. Предлагаю:
- Использовать логику названия диапазонов из HOMM 3 в качестве демонстрации множественного if-else (не все 9 диапазонов, некоторые можно объединить). Это выглядит интереснее, чем количество символов в главе :)
- Вместо этой задачи предложить студенту реализовать логику функции
std::clamp()
. Есть диапазон и число, если число попадает в диапазон, то возвращается само число. Если число больше верхней границы диапазона, то возвращается верхняя граница. И нижняя граница, если число меньше последней.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Может тогда уж расширим контекст задачи, мол "вот пишем HOMM3 аналог, нужен clamp, программировай"?
По идее логические операторы мы уже задели, чтобы написать условие вида:
if (count = 1 && count <= 4) println("мало");
Насчет всех диапазонов согласен. Можем предложить реализовать 2-3, а остальные (для примера и целостности) я ж сам добавлю?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Задача может быть любая, главное, чтобы она укладывалась в 3-4 ветки условия. Лучше чтобы студент решал задачу полностью сам. Для сокращения количества веток можно объединить диапазоны, например:
- few + several [1 .. 9] => few (несколько)
- pack + lots [10 .. 49] => pack (группа)
- horde + throng + swarm [50 .. 499] => horde (орда)
- zounds + legion [500 .. ∞) => legion (легион)
Разбивка и названия могут быть любыми, главное, не больше 4.
Кстати, логические операторы нигде ранее не упоминались в тексте. Стоит про них рассказать кратко, типа:
C++ имеет стандартный набор логических операторов: отрицание
!
, И&&
, ИЛИ||
.
Форма подачи на Ваше усмотрение, главное, чтобы читатель узнал как они выглядят в C++.
P.S. Идея использовать механики из игр хорошая! ИМХО
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
В дополнение к сказанному. Для возвращения результата лучше использовать переменную, а не println()
. Так проще будет тестировать.
} | ||
|
||
return a; | ||
## тернарный оператор |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Intey
Большая просьба! Сделайте rebase или merge на мастер, чтобы изменения шли на чистую главу. Текущая псевдозамена очень мешает при ревью.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ух, я надеялся, что мерж !162 решит эту проблему (это как раз его изменения), но UI github не может с этим справиться. Поправлю
return a; | ||
## тернарный оператор | ||
Тернарный оператор - когда хочется все в 1 строке. | ||
Его структура выглядит так: `CONDITION ? TRUE_EXPRESSION : FALSE_EXPRESSION`. Тернарный оператор, это выражение, которое вычисляется в некоторое значение, потому слева от его `CONDITION` можно поставить присваивание чему-то. Например: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Так же предлагаю договориться о форме нотации. На мой взгляд SCREAMING_SNAKE_CASE слишком кричащий :) Я бы предложил использовать что-то вроде такого:
<condition> ? <true expression> : <false expression>
Не настаиваю. Но Вам стоит договориться о форме нотации с @Microvenator
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Может, без треугольных скобок?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Может, без треугольных скобок?)
Это как больше нравится :) Видел вариант, где для нотификаций используется курсир:
condition ? true expression : false expression
string message = charsInThisChapter == 42 ? "University, it that you?": "well, that was expected."; | ||
std::println("{}", message); | ||
``` | ||
Здесь мы значение `message` устанавливаем в зависимости от |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
На мой взгляд акценты расставлены неправильно. Очень много уделено внимания как не надо использовать тернарный оператор. Лучше сместить акцент на то как надо!
Тернарный оператор очень полезен, когда нужно кратко (одной строчкой) получить результат из выражения, в котором требуется использовать условие:
const bool max = first > second ? first : second;
Как об этом лучше сказать - на Ваше усмотрение :) Главное акцентировать внимание на этом. Также нужно упомянуть, что оба выражения тернарного оператора должны иметь один тип.
Для демонстрации неправильного использования тернарного оператора достаточно одного примера с пояснением.
```cpp {.example_for_playground ci-wrap=function} | ||
const int crowsCount = 1000; | ||
string message = crowsCount != 89 ? (crowsCount != 1000 ? "неизвестно" : "легион") : "орда"; | ||
std::println("{}", message); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Желательно добавить задачу на использование тернарного оператора.
Пример выше, с определением размера вороньего табуна, можно переписать в новом виде: | ||
```cpp {.example_for_playground ci-wrap=function} | ||
const int crowsCount = 89; | ||
switch(crowsCount) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Пример неправильный. Нет ни одного break
.
@Intey @Microvenator
Может не будем рассказывать про switch-case
в этой главе? Конструкция полезная, но сильно реже используется чем тернарный оператор, а в сравнение с if-else
тем более.
И чтобы два раза не вставать, про цикл do-while
тоже предлагаю не рассказывать в данной главе.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Да. Давайте про это скипнем. А то для глав про условия и циклы ничего не останется)
Описание курса. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Этот файл пока не трогай, заполню его отдельно)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Хотел его отдельно прислать, а то постоянно терялся "кто ЦА" и так далее. Вот решил накинуть, выброшу из PR.
@@ -139,7 +139,7 @@ default: | |||
# Циклы | |||
|
|||
## for | |||
`for` как и в других СИ-подобных | |||
Один из вариантов итерации - `for`. Его структура: `for (INIT; COND; STEP_ACTION)`. Это не совсем точно, но в общем плане чаще всего оно выглядит именно так. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Intey , ты только начал составлять текст, но боюсь, что замучаю тебя комментами по стилю/подаче материала. Мне бы этого не хотелось ;)
Предлагаю взять небольшую паузу и хотя бы по диагонали полистать книжку "Пиши-сокращай". Даже если отбросить в сторону этот курс, она поможет в целом: для сильной аргументации, ярких выступлений.
Разберу три предложения твоего абзаца, чтобы пояснить, о каком стиле я говорю.
Один из вариантов итерации -
for
.
Ты кидаешь читателю ключевое слово как пирожок из печи) Представь, что ты только начал учить хаскель, и тебе вбрасывают: "Один из вариантов заведения псевдонимов - type
". Что type
?..) Конечно, дальше по тексту ты въедешь. Хоть и споткнешься о составленное таким образом предложение. Оно бы читалось проще, если бы звучало так: "Для заведения псевдонимов используется ключевое слово type
".
Его структура:
for (INIT; COND; STEP_ACTION)
.
Если с места в карьер расписывать, что это за INIT
, COND
и STEP_ACTION
, восприниматься будет тяжеловато. Перед формальным описанием напрашивается наглядный пример.
Это не совсем точно, но в общем плане чаще всего оно выглядит именно так.
В этой фразе много избыточного, но нет конкретики. Для главы курса не годится. От этой фразы можно было бы отказаться, и тогда весь абзац был бы примерно таким:
Один из вариантов организации циклов - с помощью инструкции for
. Так выглядит вывод в консоль чисел от -5 до 8 в цикле for
:
for (int n=-5; n<9; ++n) {
std::println("{}", n);
}
Внутри круглых скобок цикла for
содержатся три выражения, разделенных точкой с запятой. Трам-пам-пам и тут мы плавно переходим к общей форме for
. Которая уже не выглядит чем-то заумным, потому что до нее шел понятный пример.
@Intey не воспринимай, пожалуйста, этот коммент близко к сердцу. Мне @khva и @alexey-zakharenkov бывает по паре сотен замечаний выгружают, дело житейское)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Microvenator не волнуйся (надеюсь мы обоюдно перешли на "ты") за меня я уже отрефлексировал все это:
- ты мейнтейнер курса, я волонтер и с моей стороны пропихивать свое видение, как минимум не красиво, так еще и бессмысленно - решение принимаешь ты и это правильно
- с моей стороны были попытки "пропихивания" скорее не осознанно, просто потому, что по другому не умею. Учусь, книгу открыл и закрыл. Постараюсь побольше уделить ей внимания
- Насчет количества замечаний - главное что бы тебя это не утомило, а в целом могу их все принять
В целом, приношу извинения - подача получилась как-то слишком быстро и не сильно обдумана, я куда-то торопился как всегда.
Будет ли ок, если я паралельно с чтением книги буду накидывать дальнейшее заполнение? Брать паузу на чтение я бы не стал - при чтении будет не хватать практики, а потом уже не вспомню что было в книге.
Бранчевался от #162, потому суда включены изменения из нее.