Entry tags:
О константности. Продолжаю публикацию списка преступлений Страуса++
Свершенно мерзкое словечко const. Стоит только лишь наивно поверить, что константность лучше указывать, чем игнорировать, как код начинает пестрить этим словечком, что АхредуптусЪ русский дореволюционный буквой Ъ. А ежели где его и позабудешь - компилятор, ессно, тебя не поправит, "сойдет и так".
Между тем, совершенно понятно, что константность значения в приличном языке должна быть обеспечена по умолчанию, без всяких ключевых слов, а именно вариабельность и следует указывать.
Например,
char **a;
приличной реализации языка следует понимать как константный указатель на константный указатель на константный символ.
А, к примеру,
char var **a = getAddress();
**a = 'Ъ';
следует понимать как цепочку константых указателей на неконстантный символ (который мы, собственно, и собрались менять). И вот тут-то, если где словечко var будет позабыто, компилятор начнет ругаться практически наверняка.
Мало этого. Слово var по большому счету тоже излишне. Неконстантность значения есть, вообще говоря, преступление перед Разумом. В приличном языке оператор присваивания, меняющий значение, уместен не более, чем оператор goto. Что это за бред такой?! Вы где-то видели в математике (оперирующей символами сплошь и рядом) какой-то там "оператор присваивания"?! Оператор присваивания полностью запутывает программу, принуждая программиста отслеживать так называемые "изменения переменных" - это пострашнее отслеживания любых переходов с метки на метку. Язык Prolog же, к примеру, как и следовало ожидать, прекрасно обходится без оператора присваивания. Ибо нафиг не нужен.

Между тем, совершенно понятно, что константность значения в приличном языке должна быть обеспечена по умолчанию, без всяких ключевых слов, а именно вариабельность и следует указывать.
Например,
char **a;
приличной реализации языка следует понимать как константный указатель на константный указатель на константный символ.
А, к примеру,
char var **a = getAddress();
**a = 'Ъ';
следует понимать как цепочку константых указателей на неконстантный символ (который мы, собственно, и собрались менять). И вот тут-то, если где словечко var будет позабыто, компилятор начнет ругаться практически наверняка.
Мало этого. Слово var по большому счету тоже излишне. Неконстантность значения есть, вообще говоря, преступление перед Разумом. В приличном языке оператор присваивания, меняющий значение, уместен не более, чем оператор goto. Что это за бред такой?! Вы где-то видели в математике (оперирующей символами сплошь и рядом) какой-то там "оператор присваивания"?! Оператор присваивания полностью запутывает программу, принуждая программиста отслеживать так называемые "изменения переменных" - это пострашнее отслеживания любых переходов с метки на метку. Язык Prolog же, к примеру, как и следовало ожидать, прекрасно обходится без оператора присваивания. Ибо нафиг не нужен.
no subject
no subject
Дык, однолюб я. Т.е. жутко консервативен. Опять же, нравится мне ООП. Тот, который не во главе с Арафатом.
> (Или я воспринимаю ваш текст слишком всерьез?)
:-)))
хе-хе
"I invented the term Object-Oriented, and I can tell you I did not have C++ in mind."
-- Alan Key
Re: хе-хе
Хотя, на мой взгляд, определение выглядит устаревшим.
no subject
Кей, к примеру, определённо имел в виду объектную ориентацию программ, а не языка, понимаемого компилятором.
программы, написанные на C++, после компиляции объектно-ориентированными не являются (кроме тех редких случаев, когда все методы виртуальны, программист позаботился не отключить RTTI, и программа умеет читать свою собственную debug info).
термин "объектно-ориентированное" и звучит именно таким образом (а не, скажем, "класс-ориентированное" или "фигурно-скобочно-ориентированное"), потому что говорит об объектах. объект — это такая фигня, которая существует (то есть живёт в оперативной памяти, может быть идентифицирована, и имеет определёный тип) во время работы программы, а не её компиляции.
людям, пишущим batch-утилиты и не пользующимся никакой интроспекцией, это различие неважно. многим другим — важно.
no subject
Что до RTTI, то помимо реализации мультиметодов, напрямую в С++ неподдерживаемых и всякой базовой мелочи, вроде стриминга идетнификаторов классов, я не вижу реальной необходимости в RTTI.
Что до Debug Info - опять же применение неясно. Что такого хорошего можно поиметь с интроспеции?
no subject
как показывает опыт, объяснять необходимость подобных радостей жизни совершенно бесполезно. если припрёт — поймёте сами, если не припрёт (а припирает далеко не всех, и это абсолютно нормально) — то и ну его.
чтобы меня правильно поняли: я вовсе не утверждаю, что C++ говно, потому что не по-настоящему объектно-ориентирован (он говно по достаточному количеству иных причин, право же). объектная ориентация не есть сама по себе критерий качества. я всего лишь пытался объяснить, что (как мне кажется) мог иметь в виду г-н Кей, поскольку (как мне, опять-таки, кажется) я понимаю откуда пляшут его определения, поскольку я неплохо знаком с системами типа Smalltalk'а и Lisp'а.
no subject
И понятно, что объяснить можно тому, кто и так всё почти понимает. По крайней мере, в двух абзацах.
Может, хоть ссылочки адекватнуе кинете по интроспекции и её нетривиальной пользе для долгоживущих систем, data-oriented programming и проч? - я б почитал.
no subject
вот поглядите, скажем, на стоящее перед Вами в данный момэнт устройство типа "персональный компьютер". на нём бежит большая, долгоживущая и интроспективная по самое не могу программа, называемая "операционная система".
предположим, эта система называется "юникс" (система типа "виндоуз" отличается от системы типа "юникс", но не существенно. "юникс" в принципе сильно проще, а посему представляет из себя лучший пример). аналогом "процедур" в языке "юникс" являются бинарные программы, интерпретируемые процессором. аналогом аргументов являются строчки из коммандной строки. аналогом пойнтеров — имена файлов. аналогом структур данных — файлы. единственным типом данных, который понимает "юникс", является голая строка из байтов, у которой даже длина не указана. имеется также run-time environment, называемый "ядро операционной системы", отвечающий за разделение процедур друг от дружки, подчищание экскрементов, убиение слищком жадных до памяти процедур, и прочая.
теперь представьте, что в качестве базового языка и run-time environment'а мы имеем что-то менее идиотское чем "юникс", например Smalltalk, или Lisp, или на худой конец Java. представьте себе теперь, что на основе подобного базиса написана настоящая операционная система (примеры имели место, и вполне успешные, кстати). можно ли написать подобную вещь привычным class-oriented стилем? нельзя, поскольку все объекты, с которыми подобной программе придётся иметь дело — "manifestly typed", то есть самоописывающиеся. их тип закодирован в них самих, мы не можем рассказать его компилятору и забыть о нём.
теперь более практически: программирование на Smalltalk, Lisp, или на худой конец Java разумнее рассматривать не как "написал код, скомпилировал в маааленький исполняемый файл, отправил заказчику", а как "взял исходную систему, расширил её своей функциональностью". таким образом, философия системы естественным образом перетекает в философию приложений, реализованных на базе этой системы.
что же касается "data-oriented programming", то ничего особенно содержательного в этом понятии нет. это просто следствие из видения мира, в котором полноценные типированные объекты (а не C++-like куски памяти, тип которых когда-то знал компилятор) живут в программе, а не только в компиляторе.
если всё-таки хочется ссылок, то лучше сгрузить с сети хороший Smalltalk или Common Lisp и поиграться с ним. :)
no subject
Опять же, видимо, в силу моего ограниченного опыта, не совсем понятно, что нормальная программа (а не дебаггер-трассировщик какой-нибудь) может сделать с "полноценным типированным объектом" такого нетривиального. Есть, конечно, отдельные случаи, когда имеет смысл выяснить, поддерживает ли объект тот или иной интерфейс (C++ RTTI, COM IIDs etc.), но кажется, по большей части такая практика свидетельствует о неполноценности дизайна, который приводит к череде if-ов, разбросанных там-сям в программе и крайне тяжело поддерживаемых в больших проектах. Кажется, за такую практику Страуструп где-то и критиковал SmallTalk.
В целом ясно почти наверняка, что Вы знаете, о чем говорите :-), а мой опыт в OOP уж точно выкристализован действительно не в самом нормальном контексте С++ и не обогащен в достаточной мере иными ОО-языками. Просто пока содержательная часть ваших утверждений для меня не очень ясна - это следовало бы отметить, а не кивать головой в знак понимания того, чего я пока не понимаю.
no subject
операционные системы (кроме некоторых совсем уж ужатых embedded) позволяют пользователю (и его программам) задавать вопросы о состоянии системы, и менять параметры системы исходя из этого. скажем, пользователь может спросить, сколько свободной памяти осталось. или узнать, реализована ли в системе конкретная процедура, пороверив наличие соответствующего исполняемого файла. или спросить, какой тип у определённого файла данных. или проверить, бежит ли некая программа, и если бежит — убить.
> Опять же, видимо, в силу моего ограниченного опыта, не совсем понятно, что нормальная программа (а не дебаггер-трассировщик какой-нибудь) может сделать с "полноценным типированным объектом" такого нетривиального. Есть, конечно, отдельные случаи, когда имеет смысл выяснить, поддерживает ли объект тот или иной интерфейс (C++ RTTI, COM IIDs etc.), но кажется, по большей части такая практика свидетельствует о неполноценности дизайна, который приводит к череде if-ов, разбросанных там-сям в программе и крайне тяжело поддерживаемых в больших проектах. Кажется, за такую практику Страуструп где-то и критиковал SmallTalk.
мой предыдущий пост был достаточно сумбурен, и этот обещает быть не лучше. :)
основная идея в следующем: говоря о data-oriented programming, я не пытаюсь что-либо рекламировать. я очевидным образом не сумел сформулировать самый важный пункт: DOP не есть что-то, что получается посредством сознательного применения каких-то там специальных методик. DOP — это то, что остаётся после отказа от явных глупостей. разумеется, придерживающиеся философии DOP системы делают практичными некоторые методики, о которых в C++ и иже с ним даже думать не получается, но это уже следствие и в данном контексте менее интересно.
например, я не в коем случае не утверждаю чего-либо о [не]желательности полноценного дизайна. ясное дело, наличие дизайна объективно лучше, чем отсутствие такового. означает ли это, что система не должна в принципе допускать возможности работать иным образом?
давайте я для простоты перечислю (некоторые) фундаментальные аспекты философии C++ и иже с ним, которые я считаю глупостями:
1. тип объектов как нечто, присутствующее лишь во время компиляции. это чисто философски неприятно:
0 — это число 0, а ни в коем случае не указатель на объект, сидящий по адресу 0, и не значок с кодом 0.
"abc" — это строка "abc", а не число 1633837824 и не указатель на объект по соответствующему адресу.
если мне захочется писать на ассемблере, я найду себе ассемблер. если же я рассматриваю объекты не как куски памяти, а как объекты, то я не желаю и думать про куски памяти, и я хочу чтобы мой runtime environment помогал мне в этом.
2. тип объектов как нечто, присутствующее лишь при компиляции. это чисто философски неприятно ещё и по той простой причине, что выкидывать информацию вообще в принципе некрасиво. кто он, чёрт возьми, такой, этот компилятор, и почему он считает себя умнее меня?
вообще, C++ и иже с ним навязывают разработчику определённые глобальные оптимизации, ценность которых, мягко говоря, неочевидна, и которые предполагают что разработчик либо пишет тупые batch-утилиты, либо знает Абсолютно Всё На Свете заранее.
3. (как следствие из предыдущих пунктов) unsafe runtime environment. в наше время это просто смешно, это даже оптимизацией не назовёшь, это мазохизм чистой воды (не говоря уже о проблемах с security).
> В целом ясно почти наверняка, что Вы знаете, о чем говорите :-), а мой опыт в OOP уж точно выкристализован действительно не в самом нормальном контексте С++ и не обогащен в достаточной мере иными ОО-языками. Просто пока содержательная часть ваших утверждений для меня не очень ясна - это следовало бы отметить, а не кивать головой в знак понимания того, чего я пока не понимаю.
это правильно. :)
no subject
А именно? Что Вы имеете в виду?
> означает ли это, что система не должна в принципе допускать возможности работать иным образом?
Сложный вопрос. С одной стороны, кашу маслом не испортишь. Но вот считать RTTI и вообще интроспекцию необходимой частью OO без демонстрации сереьзных примеров применения, я бы не стал.
При этом я не отрицаю реальную необходимость RTTI в С++, как уже было сказано - но это в силу ограниченности средств языка (того же отсутствия мультиметодов), а не в силу естественности применения RTTI в OO.
Кастирование нуля в указатель итп., конечно, не очень удачно. Но почему нельзя рассматривать строки как указатели на память - именно ради оптимизации, понятно не очень. Так или иначе, понятно, что среда действительно крайне ненадёжна - мне как раз, в отличие от вас, видится, что отчасти это следствие именно оптимизации (строк и массивов вообще).
> выкидывать информацию вообще в принципе некрасиво
Слишком общее утверждение. Эдак, вы еще захотите, чтобы программе были доступны собственные исходники.
> тип объектов как нечто, присутствующее лишь при компиляции. это чисто философски неприятно
RTTI уже есть (его значение в С++ я не преуменьшаю). А что еще нужно, кроме него, чтобы тип объекта присутствовал в Run Time? Доступ к контейнеру, содержащему имена и типы всех методов объекта? :-) Или? И что мы с такой информацией такого можем сделать?
И опять же, как отсутствие типа объекта превращает делает нам "unsafe runtime environment" ?
no subject
а очень просто.
файл "ook.h":
файл "eek.h":
файл "ook.cpp":
файл "eek.cpp":
скомпилируйте ook.cpp и eek.cpp и слинкуйте вместе. ответьте на вопрос: что именно считать определением типа "a" в результирующей программе, и будет ли она работать? :)
> > делают практичными некоторые методики, о которых в C++ и иже с ним даже думать не получается
>А именно? Что Вы имеете в виду?
нетушки :). я пока ещё не убедился, что мы вообще на одном языке разговариваем. потому что если Вам кажется, что Вам (или, если угодно, Вам как (по крайней мере, отчасти) типичному представителю любителей C++) пытаются "продать" safe runtimes, то мы друг друга не понимаем.
> Сложный вопрос. С одной стороны, кашу маслом не испортишь. Но вот считать RTTI и вообще интроспекцию необходимой частью OO без демонстрации сереьзных примеров применения, я бы не стал. При этом я не отрицаю реальную необходимость RTTI в С++, как уже было сказано - но это в силу ограниченности средств языка (того же отсутствия мультиметодов), а не в силу естественности применения RTTI в OO.
I beg your pardon? объектная ориентация подразумевает типирование объектов, точка. необходимой частью принятого стиля программирования на C++ RTTI, очевидно, не является. (это одна из причин, по которым о C++ желательно забыть, ну да ладно. :))
> Кастирование нуля в указатель итп., конечно, не очень удачно.
принцип "I don't care if this is wrong, as long as this is fast" вообще не очень удачен.
> Но почему нельзя рассматривать строки как указатели на память - именно ради оптимизации, понятно не очень. Так или иначе, понятно, что среда действительно крайне ненадёжна - мне как раз, в отличие от вас, видится, что отчасти это следствие именно оптимизации (строк и массивов вообще).
строка была не самым удачным примером, поскольку в C/C++ это действительно указатель на память. давайте так: "abc" — это именно и только указатель на место, где сидят 'a', 'b', 'c' и '\0'. а не номер 67868767, не массив целых чисел, не ...
> > выкидывать информацию вообще в принципе некрасиво
> Слишком общее утверждение. Эдак, вы еще захотите, чтобы программе были доступны собственные исходники.
не захочу. система типов (и прочая интересная структурная информация) никакого отношения к исходникам не имеет и исходников для интерпретации не требует.
> RTTI уже есть (его значение в С++ я не преуменьшаю). А что еще нужно, кроме него, чтобы тип объекта присутствовал в Run Time? Доступ к контейнеру, содержащему имена и типы всех методов объекта? :-)
не вижу причин для смайлика. насчёт имён не знаю, зависит от языка. но какую-то идентификацию — безусловно. потому что method dispatch обязан принимаеть во внимание тип объекта (а не тип указателя при компиляции и т.д.). вообще-то, в случае C++, такой "контейнер" принято называть vtable.
ладно методы. вот что абсолютно необходимо, так это описание data layout'а каждого класса.
> И что мы с такой информацией такого можем сделать?
пожалуйте изучить (ещё разок) примерчик из начала данного комментария. :)
> после компиляции объектно-ориентированными не являю
Re: > после компиляции объектно-ориентированными не яв
извините. :)
> пытался объяснить оригинальное (т.е. согласно Алану К
> извините. :)
np :-)
no subject
no subject
У вас есть какое-то разумное объяснение, почему в программе переменные - вторичны, а константы - первичны?
no subject
no subject
Вот посчитал по прожекту число присваиваний:
---------- DB_LAYER.CS: 225
---------- EFT.CS: 41
---------- TMS_MANAGEMENT.CS: 28
---------- TREASURYMONITORSERVICE.CS: 137
---------- TREASURYMONITORSERVICE_AIRTIME.CS: 79
---------- TREASURYMONITORSERVICE_LOYALTY.CS: 49
---------- TREASURYMONITORSERVICE_SPUR.CS: 33
---------- TREASURYMONITORSERVICE_TRANSACTION.CS: 144
---------- TREASURYMONITORSERVICE_VOUCHERS.CS: 35
Я бы сказал, не так уж и мало! Часть, так и быть, инициализация (хотя у меня большинство констант сидят в enum), но остальных присвоений тоже немерянно!
Я хочу сказать так: ни var, ни const не спасает от банально тупых алгоритмов. Куда больше гемороя приносят неочевидные "особенности" чужих функций.