Здравствуйте, vdimas, Вы писали:
V>>>И прочие GOF-трюки, где иммутабельность может быть св-вом объекта, а может быть адаптером-view.
V>·>Иммутабельность нельзя через view обеспечить.
V>Обеспечить-то программным образом можно, ес-но.
Нет, нельзя. Ты не можешь сделать иммутабельный view к мутабельному объекту. Вообще никак, это просто бессмысленно. Можно сделать read-only view, но не иммутабельный view.
V>Нельзя обеспечить, скажем, контроль иммутабельности со стороны компилятора, т.е. нельзя задать гарантии через ср-ва языка.
Можно создать иммутабельный объект копируя мутабельные данные, ну или через передачу владения, собственно всё. Ну или если у тебя какой-нибудь rust с borrow checker.
V>·>Ты тоже что-ли путаешь константность и иммутабельность?
V>Применительно к данным — это одно и то же.
V>Применительно к ссылкам/указателям на данные — необходимо уточнять, что имеется ввиду — константность указателя или самих данных.
Указатель — это тоже вид данных, не надо мудрствовать.
V>Константность можно добавлять неиммутабельным данным по ссылке/указателю, убирать константность нельзя.
V>То бишь, для любых константных данных их иммутабельность автоматически гарантируется.
Иммутабельность гарантируется только тогда, когда к данным нет легального способа получить мутабельный доступ.
V>Код, принимающий аргументы по константной ссылке или указателю, может быть одинаков для иммутабельных и неиммутабельных объектов (в части их const-интерфейса) — как прямое следствие возможности добавления к типу модификатора const по указателю/ссылке.
Это не достаточное условие. У типа должны быть какие-то определённые const-методы (или, другими словами, const-интерфейс). Иначе наличие такой ссылки тебе ничего не даст, т.к. не сможешь ничего сделать. В чём разница с интерфейсами — неясно.
V>·>Константность означает, что объект нельзя поменять. А иммутабельность, что объект не может поменяться.
V>ха-ха
V>Это в тебе говорит прокуренность джавой, где ты вместо переменной ссылочного типа видишь сам объект за ним.
Ерунда какая-то. В точности наоборот, в джаве все объекты — только по ссылке.
V>В плюсах такая константность раздается независимо как переменной-указателю, так и указуемым данным:
V>V>const SomeObj * const obj = getObj();
V>
V>Переменная obj является иммутабельной, инициализирована указателем на
ну в случае
final SomeObj obj = getObj() в яве тоже, переменная тоже "иммутабельная". Правда толку маловато будет. Применять термин Иммутабельность к переменной — как-то бессмысленно, только для разведения демагогии годится. Мутабельность-иммутабельность обычно относится к состоянию объекта.
V> объект типа const SomeObj.
Ага. А вот тут уже интереснее — именно что
const-объекта, но про иммутабельность — ичсх ты промолчал. Демагогия, ЧТД.
V> Насчёт "значительно" перебор, ИМХО, бо правила вокруг const просты, даже слишком.
Только что тут флейм был на сотню сообщений что где когда с константностью происходит. Ага, ага, всё просто.
V>·>Но я от этого спора уклонюсь.
V>Потому что спор бесполезный.
Потому что бесмысленный, основанный на субъективщине и вкусовщине.
V>Сравнивалась выразительность языков, где бесполезно сравнивать декларативные пометки внутри одного класса с описанием доп. классов (разделение на builder и immutable-версии одной и той же структуры данных).
Если ты таки поймёшь разницу между константностью и иммутабельностью, то поймёшь, что в плюсах ситуация ровно такая же.
V>>>Так мы только выразительность языков и обсуждаем.
V>·>Обсуждение началось с вопроса о том, что константность вещь очень важная и нужная и в других ЯП без неё всё плохо.
V>Больше работы — плохо.
А в чём работу меряешь-то? Пишешь record, вешаешь @Builder аннотацию и готово. Да даже без этого, с современной IDE работу делает железяка, а не программист.
V>·>Мой тезис в том, что это вовсе не так, и множество других ЯП прекрасно обходятся без константности.
V>1. Обходятся за счёт лишнего труда программиста.
Этот труд давно автоматизирован и поэтому не программист трудится.
V>2. Присутствует принципиальная сложность обеспечить константность для ссылочных типов, иначе это было бы давно сделано.
V>Спроси меня "почему?" — растолкую подробно, почему в C# аналог const есть только для структур, но не может быть применён к классам.
Потому что они статик? Имхо, просто ошибка в проектировании семантики языка.
V>Это не в недостатке машинки дотнета дело, а в семантике ссылочно-ориентированных языков.
Ну в общем-да. Но ты говоришь, как будто это что-то плохое, называешь недостатком.
V>·>Ты ... путаешь константность и иммутабельность?
V>Применительно к данным — это одно и то же.
В этом случае есть final в джава. Но это неинтересный случай, а демагогия.
V>>>И в правилах языка, где константные методы можно вызывать у неконстантного объекта, а наоборот нет.
V>·>В шарпах-явах то же самое выражается в виде системы типов с интерфейсами и наследованием.
V>Но компилятор умывает руки, бо это контракты прикладного уровня, которые легко нарушить.
V>Плюсовые контракты нарушить сложнее во много раз.
V>(разве что через реинтерпретацию/хак памяти, но аналогичные ср-ва есть и в дотнете, и в джаве, вроде)
В целом да, цена универсальности. Зашивать конкретный контракт в спеку ЯП — очень тяжелая артиллерия. Имхо, в данном случае, неоправданная. Но это _имхо_. Спорить не буду.
V>·>Насчёт выразительности — читая этот код — здесь это никак не выражено. И никак не проверяется компилятором. Завтра вася поменяет определение logCollection, потеряет или сломает константность — и приехали.
V>Сломает через хак, если.
V>А законными ср-вами сложно.
Какой хак? Было logCollection(const X&), потом вдруг немного что-то понадобилось где-то и поменял на logCollection(X&), а код всё ещё компиляется как ни в чём не бывало. А в плюсах ошибка в размере типично ведёт к UB и оно даже может как-то работать.
V>>>for(size_t i = 0; i < size; i++) // незачем запрашивать размер коллекции заново
V>·>Ну это удобство для компилятора, а не для человека. В яве с этим мучается обычно JIT.
V>JIT и компиляторы не всесильны, они хорошо работают только в простейших случаях (где никакого const и не надо, бо компилятор и без сопливых видит жизиненный цикл данных).
V>Обсуждаемое помогает именно там, где никакой JIT и компилятор уже не справляются.
Ну идея JIT в том, что таких простейших случаев 99.9%, а там где оно не справилось, там попрофилируем и пооптимизируем вручную.
V>·>В каком смысле "одно"? Можно описать в соседних строчках файла? Или что? Чем описание интерфейса "другее"?
V>Тем, что по интерфейсу не гарантируется иммутабельность — компилятор умывает руки.
Иммутабельность (не путай с константностью) и в плюсах ничем не может гарантироваться. Ты сам вроде это мне доказывал. А аналог const есть и в java в виде final.
V>А если в плюсах создал const-объект, то он достоверно иммутабельный (с точностью до замечания о распространении константности по ссылочным полям, где решение я давал).
А как ты достоверно создашь const-объект-то? Ну тот же std::map, например? В лучшем случае через defensive copy или через передачу владения. Ровно так же как и в шарпах-явах.
V>>>А вот если речь должна идти про сами типы-коллекции, то появляются пары Span/ReadOnlySpan, Memory/ReadOnlyMemory и т.д.
V>·>И что в этом плохого-то? Чем таким принципиально важным "const Span" отличается от "ReadOnlySpan"?
V>Тем, что достаточно было одного типа Span, некоторые св-ва и методы которого помечены как const (и эти методы и св-ва уже и так присутствуют, просто без пометки).
Я имею в виду с т.з. программиста? Реальная причина в том, что им приходится Span делать как struct и избегать боксинга, т.е. просто реализовать ифейс они не не могут. Проблема в компиляторе, в оптимизации, а не в выразительности для человека.
V>>>И это еще в шарпе по-лёгкoму, т.к. язык позволяет определять операторы преобразования, поэтому смогли определить неявное конструирование ReadOnly-версий из мутабельных.
V>>>В джаве пришлось бы делать двойную работу, окучивая каждую пару.
V>·>Ну в джаве в похожем месте другой дизайн — там буферы, readonly означает, что можно читать данные (при этом сам буфер как объект меняется — сдвигается position и т.п.), но записывать данные нельзя. Что-то похожее на memory mapped file, открытый с ro-правами.
V>В этом случае достаточен readonly итератор, т.е. некий view над иммутабельными данными.
Ну там довольно сложный набор методов — взятие данных различных размеров, по разным позициям и т.п. По сути итератор и есть, но очень навороченный, заточенный для обработки бинарных блоков.
V>>>Не, final-метод в джаве обозначает другое.
V>·>final-поле и final-переменная я имею в виду.
V>Бгг, что намекает о том, что пользовательских value-типов в джаве никогда не будет. ))
Ну вроде Valhalla пилят, правда с низким приоритетом...
V>Ведь в шарпе повторили семантику const для них, где соотв. методы помечены как readonly, т.е. другое ключевое слово (аналог final-классов и final-методов в шарпе sealed).
Не понял что к чему.
V>>>Суть в том, что иммутабельность — такой же "трюк", облегчающий программистам жизнь, как и куча других.
V>·>Разговор о том, насколько этот трюк необходим, начался разговор с того, что "как же в других ЯП без него обходятся", я рассказал как.
V>И малость засверкал наивностью, бо все и так прекрасно в курсе, как обходятся в других ЯП.
V>А ты стал лишь подтверждать исходные тезисы. ))
V>(Вряд ли для плюсовкиа его язык единственный или хотя бы первый, для нашего поколения он шёл обычно вторым-третьим языком, т.е. на плюсы подсаживались обычно более чем сознательно).
Судя по обсуждению — далеко не все в курсе.
V>>>А вот почему более поздние джава и шарп оказались не готовы — вопрос вопросов, однако.
V>·>В java есть record, давно уже готово.
V>Ну какой давно, пару лет еще не прошло.
До этого — lombok если очень хотелось.
V>В котлине дата-классы давнее.
И в scala case-классы ещё давнее.
V>И это закрывается только малая часть сценариев вокруг иммутабельности.
А что не закрывается?