Однажды один волшебник нашёл восхитительное заклинание. Берёшь два чашки, в одной из которых чай.
- Ставишь на заколдованные блюдца на заколдованной скатерти.
- Говоришь на загадочном языке «поставь эту чашку на это блюдце» — указывая сначала на чашку, затем на блюдце.
- И перед нами стоит две чашки чая, как будто бы чай скопировался. Очень полезное заклинание.
Если скажешь «поставь вот это блюдце на вот эту чашку» — ничего не выйдет. Как можно блюдце поставить на чашку?
Это как в программировании, в команде присвоения указать
a = 5
— можно.А указать,
5 = a
— в общем-то, бессмысленно.Про чашку, конечно, можно сказать «чашка вот с этого блюдца», и указать на блюдце. И тоже всё сработает. Это как
a = b
. Но, указывая куда ставить, нужно говорить именно о блюдце. И вообще, все чашки, которые вы не держите в руках, должны иметь соответствующее блюдце, потому что скатерть заколдована — на ней чашки без блюдца опрокидываются.Ещё задолго до этого открытия уже существовали волшебные чайники — заливаешь туда две чашки чая разного вкуса, а из него получается одна чашка чая нового вкуса. И если до этого было как-то жалко, что чая становится меньше, то после обнаружения заклинания копирования это перестало быть проблемой и стало можно устраивать волшебные чаепития. Вот о них я и расскажу.
Блюдца заколдованы так что принадлежат своим хозяевам. То есть, надо приходить на чаепитие со своими блюдцами. И милая особенность в том, что как только гость встаёт из-за стола и выходит на улицу, все блюдца оказывается у него с собой. Очень удобно.
Обычно гость приходит, садится, достаёт свои блюдца и ему на них копируют чашки чая. Наверное, лучше сказать «переливают» — такое название привычней. Он чай пробует, оценивает. И решает угостить хозяйку в ответ. Он в волшебный чайник заливает с одной стороны чай, который он сейчас пробовал, с другой стороны тот чай, который принёс с собой, и полученный чай «переливает» в чашку хозяйки. Точнее, в чашку на блюдце хозяйки. И в целом, всё. Он и угостился и угостил, может уходить. Прямо как функция в программе, обработала аргументы, вернула результат — и свободна.
Но можно заметить, что чем больше чашка, тем дольше переливание. А есть и такие люди, которые торопятся.
Для них можно вспомнить, что вместо переливания можно передавать чай в чашке прямо на блюдце. Это быстрее — хозяйка даёт чай на своём блюдце, гость пробует, смешивает со своим чаем, возвращает хозяйке чай на том же блюдце и может быть свободен. Напоминает передачу в функцию аргументов по ссылке.
f(Type & arg)
.Функция может даже и без аргументов возвращать значение по ссылке.
Type & f()
. Это как если бы гость после того как произвёл в чайнике новый вкус, отдал бы его хозяйке на своём блюдце. А потом бы встал из-за стола, вышел на улицу, пошёл бы дальше, а из дома раздался бы возглас ужаса хозяйки — блюдце гостя со стола исчезло, волшебная скатерть перевернула чашку без блюдца. Теперь там большая лужа. Попили чай, называется.Волшебника, который придумывает заклинания, попросили придумать что-нибудь, чтоб такого не случалось, и он сделал даже больше.
На загадочном языке блюдце называется
lvalue
, а чашка rvalue
. А волшебник добавил в заклинения ещё слово xvalue
. Это слово тоже означает «чашка», но такая чашка, которая обязательно находится на таком блюдце, которое принадлежит хозяйке. Точнее, тому кому будет отдано. Получается, тут ещё магия предвиденья. И тогда гостю не обязательно «переливать» чай, чтобы возвратить хозяйке. Достаточно чтобы блюдце, которое он оставит, таким образом передарилось.Кроме того, волшебник для удобства создал целостное заклинание угощения. И ещё добавил возможность помечать блюдца меткой «X», «чай можете забрать». Такие сразу образуются под чайником. Это как добавить
rvalue
-ссылки в программировании f(Type && a)
. О, и название у ссылок даже такое же. Забавное совпадение.Угощение происходит так: заклинания надо произносить с обеих сторон. Гость говорит, как он примет чай: через «переливание»
f(T arg)
, или вместе с блюдцем f(T & arg)
, или обменявшись f(T && arg)
. Можно пообещать не пить из чашки. f(const T & arg)
. А хозяин указывает на чашку — на обычном блюдце или помеченном. И происходит процесс. Быстрее всего происходит передача хозяйского блюдца, на втором месте обмен с помеченным блюдцем. Обмена с блюдцем, которое не помечено, у гостя таким образом не получится, потому что именно пометка «чай можете забрать» и составляет разрешение хозяина на такой обмен. Наверняка, в заклинании установки метки встречается слово move
. По крайней мере, в программировании используется именно это слово.На одно чаепитие пришёл гость не один, а с двумя детьми. Он хотел узнать, как в деталях работает заклинание, ведь его дети сели на одно место, но блюдца у них были свои. Один ребёнок сказал «мне передать на блюдце», другой «а мне обмен». Гость сам у хозяина получил чашку через обмен. И заметил следующее: если просто говорить «тоже обмениваюсь с детьми», то чашка на блюдце уходит первому ребёнку, а если говорить «с этого блюдца чай можете забирать» и затем «обмениваюсь с детьми», то обмен происходит со вторым.
Ещё гость заметил, что если своё блюдце передать первому ребёнку, тот может его отдать кому-нибудь «и когда мы уйдём, может случиться ещё одна лужа». Но если хозяин передал чай на своём блюдце, то быстрее и вполне безопасно его передавать первому ребёнку, а не обмениваться со вторым. То есть, в этом случае добавлять пометку «чай с блюдца можно взять» не нужно.
А если хозяин вдруг запретит пить из чашки, то передать детям нужно с таким же запретом. Тогда чай получит тот ребёнок, который согласится сам себе «перелить», оставив в хозяйской чашке то что там было.
Помнится, гость тоже оказался колдуном, он начал колдовать заклинание «шаблон». И вставлял фразы заклинаний обмена с хозяином и с детьми. Только, там где надо было решать, вставлять ли
move
, он сказал forward<T>
. И на месте гостя появился какой-то дубль. Он брал чай у хозяина таким образом каким было удобно хозяину, и передавал детям самым подходящим образом. Интересно то что у «шаблона» в заклинании запрос на обмен хоть и был обменом, f(T && arg)
, но когда хозяин предлагал забрать чашку с блюдцем, то передача всё равно срабатывала. Колдун на вопрос «почему так?» сказал, что у «шаблона» (T=type&)&&
значит type&
, & && -> &
. Я этот магический язык знаю и мне всё сразу стало понятно.Пойду сам чай попью.
Комментарии (36)
vadimr
28.08.2022 11:48+9Даже зная что такое переменные и rvalue/lvalue, описанный мир возникающих ниоткуда волшебных чашек я понять не осилил, даже прочитав несколько раз. Ни в отрыве от программирования, ни по аналогии.
Я даже не смог понять, что именно (и кому) объясняет автор – способ вычисления значения выражения или систему статической типизации.
Статья является примером, как можно предельно запутать несложный вопрос.
yurixi Автор
28.08.2022 14:13-4возникающих ниоткуда волшебных чашек
В программе постоянно из одних значений получаются новые, а при передаче в функцию по значению происходит копирование. Необычность, если она и есть, заключается не в данном мной описании, а в том, что в программах именно так всё и происходит.
Возможно, вам из-за того что простые вещи кажутся очевидными, не понять, как людям только осваивающим абстрактную область сложно приспособить свою бытовую интуицию. Но уж говорить что всё усложнено — это уже явная мнительность.
Но в целом, очень благодарю за комментарий! Я даже не предполагал, что такие мнительные люди считают себя вправе что-то оценивать.vadimr
28.08.2022 14:16+1Так у вас чай копируется или чашки с чаем? Я уже этого не смог понять из текста.
А оценивать я уж точно вправе, отучившись в аспирантуре по программированию :)
yurixi Автор
28.08.2022 14:19-6Смешно. Аспирантура по программированию даёт вам право оценивать? Я себе обещал над вами не насмехаться, так что не буду на это отвечать.
А в аналогии чай и чашка чая одно потому что чай без чашки в воздухе не удерживаться. Вы этого не поняли проучившись в аспирантуре. Ну так и какие выводы?
Хотя, если без усмешек, в первой же части видно что чашка копируется целиком. Разве нет?vadimr
28.08.2022 14:25+5Если вы считаете целесообразным надо мной насмехаться, то делайте это, сколько сочтёте нужным, я не обижусь.
Аспирантура – это именно то место, где присваивается право преподавания теоретических дисциплин в высшем учебном заведении и, соответственно, оценивания знаний по вузовским дисциплинам, к которым относятся теоретические вопросы программирования. Это вам для справки.
А если для вас чай и чашка чая – одно и то же, то у вас очень неконкретное мышление, которое в данном случае мешает построить правильную аналогию в таком формальном вопросе.
Если значение – это сам чай, то откуда при копировании значений у вас возникают чашки на блюдцах? Если же значение – это чашка с чаем, то что в ваших аналогиях означает упомянутая далее операция переливания?
Все эти мысли мне отчасти напомнили рассуждения пелевинского Чапаева о форме самогона, но программирования в этом мало.
yurixi Автор
28.08.2022 14:38-5Вы знаете, у меня мало опыта общения с образованными, но мнительными людьми, за одно — они стоят уважения, за другое не стоят. То что вы окончили аспирантуру — для меня не основание уважения и прислушивания к мнению. И вряд ли вам с этим стоит спорить.
Давайте вырулим разговор на что-нибудь полезное? Вряд мне вам получится указать на ваши заблуждение. Ну вот, что вы себя зря апломбировали — это уже и так понятно, но разве вы согласитесь?
Я могу лишь согласиться что в статье это действительно не формальное и не учебное объяснение. А вот то что не полезное, или вредное — это уже просто ваше «верьте мне я доктор». Хотя уровень аргументации уже очевиден.vadimr
28.08.2022 14:42+3Вам выше правильно указали более подходящую аналогию с коробками спичек. Как минимум, по четырём причинам. Спички помещаются внутрь коробка, спички дискретны, ценность одинаковых спичек безусловно заключается в их количестве, и отсчитать в другой коробок равное количество спичек для копирования можно, не прибегая к волшебству.
Касательно аспирантуры. Вы упомянули впрос, ВПРАВЕ ли я что-то оценивать. ПРАВО оценивать (в формальном, юридическом смысле) даёт именно аспирантура, о чём я вам и ответил. А в гражданском смысле право оценивать есть у каждого. Ваше уважение и внимание к моему мнению – другое дело, ваше личное, меня оно не очень касается.
yurixi Автор
28.08.2022 14:50Полезность объяснять числа через числа очень сомнительна.
Полезность объяснять свойство вложения через невозможность обратного вложения оставляет выбор не за тем кто так делает. Здесь свои минусы. Тоже объяснение через себя.
Волшебство в статье заключается только в том что суммарный объем чая не сохраняется и блюдца вначале самостоятельно собираются с собой — это не на столько переполняет воображение как вы хотите показать.vadimr
28.08.2022 14:54+1А в задачу статьи входило ещё и объяснить понятие числа?
yurixi Автор
28.08.2022 14:59ценность одинаковых спичек безусловно заключается в их количестве
Ну вот это — разе достоинство в контексте статьи?vadimr
28.08.2022 15:07Конечно, вы же значение переменной оцениваете исключительно по записанному по её адресу двоичному числу. У одного человека 20 спичек и у другого 20 спичек той же марки.
А чай если переливать из чашки в чашку, да ещё когда по пути разные люди прихлёбывают и его пробуют – он заведомо изменит свои свойства.
yurixi Автор
28.08.2022 15:13+1Ну здесь основное свойство чая — это его вкус, который меняется через чайники. Не количество, а качество. Переменные же — тоже, на низком уровне числа, а потом уже может быть что угодно, RGB цвет, например. Так что если не надо было объяснять количество — так и объяснялось качество.
Может вы просто с непривычки так среагировали? К своим-то аналогиям привыкли.
vadimr
28.08.2022 15:32+1Я сразу написал, что вообще не смог понять построенную Вами аналогию и объясняемый ею предмет. Поэтому вопрос тут не в привычке, тем более что о спичках я точно так же впервые прочёл сегодня на этой странице.
С тем, что переменные содержат вкус или цвет, я не согласен. Переменные содержат свои значения, то есть двоичные числа в памяти. А уже эти значения могут использоваться архитектором программы для представления цвета, но это совершенно другой вопрос, не касающийся семантики языка программирования.
Поэтому благородные мужи древности сказали бы, что не надо уподоблять такую низкую вещь, как устройство компьютера, такой высокой вещи, как чайная церемония :)
Честно говоря, вопрос, который Вы вскользь поднимаете в конце текста, касательно отличия семантики копирования от семантики перемещения, вообще затруднительно объяснить бытовыми аналогиями, потому что это в чистом виде вопрос вычислительной эффективности программного кода. Никакая семантика перемещения вообще не нужна, если абстрагироваться от затрат на память и на работу сборщика мусора.
yurixi Автор
28.08.2022 14:16-2То что плохая аналогия плохая и так понятно, но я писал исходя из своей оценки что аналогия хорошая. Я бы хотел пояснений, почему она плохая. Причём, пояснения в том что не хватает деталей — это уже не основание, потому что аналогия потому аналогия, что от неважных деталей отстраняется.
Я бы сказал даже больше — лично мне конкретно такого объяснения и не хватало в своё время. Все объяснения были основаны не на аналогиях а на то что кто-то что-то придумал и его объяснениям надо просто верить.randomsimplenumber
28.08.2022 14:56+1Я бы хотел пояснений, почему она плохая.
В основном потому что она ничего не объясняет, а только запутывает. Гость, который уходит и забирает с собой чашки - это что за персонаж, например?
Сборщик мусора? Тогда это совсем не отсюда. Куда он уходит, что он там делает с чашками, и что происходит с чаем?Пример со спичечными коробками лучше.
yurixi Автор
28.08.2022 15:02-1Ну как же. Если читать статью не как справочник, а как историю, то всё понятно — гость это просто человек, который попил чай и ушёл. Это всё что он делает. В аналогии это функция. И это даже не надо придумывать, это написано прямо. Отельный абзац отмечает удобство что блюдца собираются с собой — кто бы так не хотел? Что может быть непонятного?
Apoheliy
28.08.2022 18:56+2После пары+ банок пива появились вопросы: зачем гостям ходить со своими блюдцами, если частенько чайник выдаёт новые блюдца с пометкой. Весь смысл наличия своих блюдец (как обязательного условия прихода в гости) теряется. Если же чайник работает без своих блюдец, то как под чайником могут получаться чашки с новым чаем, которая и не в руках и не на скатерти+блюдце?
Если смешивание двух чаёв большого объёма требует большего времени, то почему копирование (что можно представить как переливание из чайника из одной чашки (вторая пустая (интересно, такие могут существовать?))) не даёт такого эффекта?
Гость (по лору) может угостить хозяйку своим чаем. Как он появился у гостя? Принёс с собой? Тогда зачем таскать блюдца, если можно принести с собой чашки с чаем?
Может ли гость дополнить принесённую с собой чашку чаем из чайника и унести на своём блюдце на другое чаепитие и там отдать хозяйке (только чашку)?
yurixi Автор
28.08.2022 19:52Блюдца у чайника образуются, метка звучит «чай можно взять». Наверное, стоило описать, что с них можно только брать, они после этого могут исчезнуть. Особенно те которые от чайника — они же ничьи.
Получается, чтобы на блюдце что-то ставить, нужно иметь блюдце.
Второй вопрос. Время занимает копирование оно же переливание, а сколько чайник — это уже от чайника зависит. Может и мгновенно. Здесь чайник это аналогия встроенных функций. Всего их разнообразия.
Третий вопрос. Ну да, гость может приходить со своим чаем. Начальные значения для переменных в функциях — могут же быть. Чашки с чаем принести с собой можно, но на стол их без блюдец не поставишь. Хотя, наверное, можно держать в кармане и копировать при надобности. Как константы.
Четвёртый. Может. Только, это будет функция, которая не просто вызывается несколько раз, но ещё и хранит между вызовами состояние. Такое существует, но это не обычная функция.randomsimplenumber
28.08.2022 22:18+1Жаль, нет никакой инфографики, чтобы сопоставить аллегории с чашками и блюдцами с одной стороны, и конструкции на С++ с другой стороны. Я ниасилил.
saipr
Это всё зависит от языка. Например, в tcl я могу и переменной а присвоить 5 и переменной 5 присвоить a:
И всё будет нормально. И это позволяет красиво программировать многие вещи.
SteamEngine
#define TRUE FALSE //Happy debugging suckers
PrinceKorwin
Я с вами отчасти согласен. Некоторые вещи TCL позволяет сделать очень изящно. Но! За такие изящества обычно сильно бьют в командной разработке :)
Мне TCL своей простотой и идеей очень понравился. Как язык для самовыражения и получения удовольствия он хорош. Но писать что-то коммерческое или командой я бы не стал. Тем не менее это мой любимый язык.
saipr
Мой тоже любимый язык.
yurixi Автор
Я для себя хотел пояснить rvalue ссылки на C++. Для этого искал аналоги и описал их. Тест в общем то писался для себя. Если воспринимать текст в отрыве от этой темы, то, конечно, с первых же слов захочется проверить, как смотрится блюце на чашке. А то что блюдце это аналог места в памяти не написано и может ускользнуть при чтении.
Может быть сложно аналогию разобрать, или я плохо описал её, или сама аналогия не стоящая, но статья в минусе, а в комментарии обсуждения того, что число и буквенное значение можно приравнять не обращая внимание на направление равенства. Ну, в целом, в математике так и есть. Но тема различия сторон в присваивании и правосторонних ссылок это, наверное, развитие языка, а не какие-то ограничения возможностей.
saipr
На мой взгляд, более приемлемым аналогом здесь был бы спичечный коробок:
yurixi Автор
Разумеется, но функция под свои переменные выделяет память, а потом её очищает. Можно вернуть участок памяти, в виде указателя, а потом это память очистится. То есть, в аналогии с блюдцами, забрать блюдца с собой. Понятно, что это приведёт к ошибкам. Без этого разницы между блюдцем и коробком особо-то и нет.
saipr
Конечно нет, за исключением того, что спичечный коробок, в котором лежала спичка, невозможно засунуть в спичку, которая лежит в этом коробке, а вот блюдце, на котором стояла чашка. можно легко поставить на чашку. под которой оно только что лежало. Мы же говорим про аналогии...
vadimr
Вопрос здесь не в различии сторон присваивания, а в том, что численный литерал в большинстве языков всегда имеет значением самого себя.
Это предельно ясно в синтаксисе Лиспа и производных от него языков. 5 – это то же самое, что '5, а вот a – это в общем случае не то же самое, что 'a.
А оператор присваивания – это просто частный случай. Он действительно так устроен в языке Си, что у него правая и левая части вычисляются по разным правилам, но дело не в нём.
NeoCode
Какие например?
saipr
Например? Вам необходимо хранить информацию и нескольких процессах или свойствах графических объектов. Создаете для каждого такого объекта массив или список, где идентификатором массива/списка выступает id процесса или графического объекта на холсте.
NeoCode
Непонятно. Там был комментарий saipr
Меня очень удивило, что значит "переменной 5 присвоить a", что это вообще может значить? Что такое "переменная 5", если это литеральная константа? Что произойдет в программе, если язык программирования все-же позволит осуществить такое присваивание? Чему будет равна константа 5 после этого?
saipr
Просто выполните приведённый пример и всё увидите. Прочитайте описание tcl.
Я зык программирования tcl прекрасно понимает где литерная консанта 5, а где переменная с идентификатором 5.
KanuTaH
В Tcl то, где переменная, а где - литерал, зависит от контекста:
Никаких неоднозначностей не возникает.
randomsimplenumber
Имя переменной может быть и цифрой? Непривычное.
KanuTaH
В Tcl вообще нет понятия "цифра" или "число", есть только "строка". С его точки зрения 1234 - это точно такая же строка как и ABCD, никакой принципиальной разницы между ними нет. Просто в некоторых контекстах, скажем, в рамках выражения
expr 1 + 2
, строки 1 и 2 могут интерпретироваться как числа.