yigal_s: (Default)
yigal_s ([personal profile] yigal_s) wrote2004-05-29 01:05 pm
Entry tags:

О константности. Продолжаю публикацию списка преступлений Страуса++

Свершенно мерзкое словечко const. Стоит только лишь наивно поверить, что константность лучше указывать, чем игнорировать, как код начинает пестрить этим словечком, что АхредуптусЪ русский дореволюционный буквой Ъ. А ежели где его и позабудешь - компилятор, ессно, тебя не поправит, "сойдет и так".

Между тем, совершенно понятно, что константность значения в приличном языке должна быть обеспечена по умолчанию, без всяких ключевых слов, а именно вариабельность и следует указывать.

Например,
char **a;
приличной реализации языка следует понимать как константный указатель на константный указатель на константный символ.

А, к примеру,

char var **a = getAddress();
**a = 'Ъ';


следует понимать как цепочку константых указателей на неконстантный символ (который мы, собственно, и собрались менять). И вот тут-то, если где словечко var будет позабыто, компилятор начнет ругаться практически наверняка.

Мало этого. Слово var по большому счету тоже излишне. Неконстантность значения есть, вообще говоря, преступление перед Разумом. В приличном языке оператор присваивания, меняющий значение, уместен не более, чем оператор goto. Что это за бред такой?! Вы где-то видели в математике (оперирующей символами сплошь и рядом) какой-то там "оператор присваивания"?! Оператор присваивания полностью запутывает программу, принуждая программиста отслеживать так называемые "изменения переменных" - это пострашнее отслеживания любых переходов с метки на метку. Язык Prolog же, к примеру, как и следовало ожидать, прекрасно обходится без оператора присваивания. Ибо нафиг не нужен.

[identity profile] cmm.livejournal.com 2004-05-29 02:06 pm (UTC)(link)
а не надо ссылочек.
вот поглядите, скажем, на стоящее перед Вами в данный момэнт устройство типа "персональный компьютер".  на нём бежит большая, долгоживущая и интроспективная по самое не могу программа, называемая "операционная система".
предположим, эта система называется "юникс" (система типа "виндоуз" отличается от системы типа "юникс", но не существенно.  "юникс" в принципе сильно проще, а посему представляет из себя лучший пример).  аналогом "процедур" в языке "юникс" являются бинарные программы, интерпретируемые процессором.  аналогом аргументов являются строчки из коммандной строки.  аналогом пойнтеров — имена файлов.  аналогом структур данных — файлы.  единственным типом данных, который понимает "юникс", является голая строка из байтов, у которой даже длина не указана.  имеется также run-time environment, называемый "ядро операционной системы", отвечающий за разделение процедур друг от дружки, подчищание экскрементов, убиение слищком жадных до памяти процедур, и прочая.
теперь представьте, что в качестве базового языка и run-time environment'а мы имеем что-то менее идиотское чем "юникс", например Smalltalk, или Lisp, или на худой конец Java.  представьте себе теперь, что на основе подобного базиса написана настоящая операционная система (примеры имели место, и вполне успешные, кстати).  можно ли написать подобную вещь привычным class-oriented стилем?  нельзя, поскольку все объекты, с которыми подобной программе придётся иметь дело — "manifestly typed", то есть самоописывающиеся.  их тип закодирован в них самих, мы не можем рассказать его компилятору и забыть о нём.
теперь более практически: программирование на Smalltalk, Lisp, или на худой конец Java разумнее рассматривать не как "написал код, скомпилировал в маааленький исполняемый файл, отправил заказчику", а как "взял исходную систему, расширил её своей функциональностью".  таким образом, философия системы естественным образом перетекает в философию приложений, реализованных на базе этой системы.
что же касается "data-oriented programming", то ничего особенно содержательного в этом понятии нет.  это просто следствие из видения мира, в котором полноценные типированные объекты (а не C++-like куски памяти, тип которых когда-то знал компилятор) живут в программе, а не только в компиляторе.
если всё-таки хочется ссылок, то лучше сгрузить с сети хороший Smalltalk или Common Lisp и поиграться с ним. :)

[identity profile] cmm.livejournal.com 2004-05-30 02:27 am (UTC)(link)
> Аналогии понятны, но в чем состоит интроспективность операционной системы, из вашего поста мне не было ясным.

операционные системы (кроме некоторых совсем уж ужатых 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 уж точно выкристализован действительно не в самом нормальном контексте С++ и не обогащен в достаточной мере иными ОО-языками. Просто пока содержательная часть ваших утверждений для меня не очень ясна - это следовало бы отметить, а не кивать головой в знак понимания того, чего я пока не понимаю.

это правильно. :)

[identity profile] cmm.livejournal.com 2004-06-03 10:18 am (UTC)(link)
> И опять же, как отсутствие типа объекта превращает делает нам "unsafe runtime environment" ?

а очень просто.

файл "ook.h":
struct a {
  int x;
};


файл "eek.h":
struct a {
  int y;
  int x;
};


файл "ook.cpp":
#include "ook.h"

struct a *
make_new_a () {
  return new struct a;
}


файл "eek.cpp":
#include "eek.h"

struct a *make_new_a ();

int
main (int argc, char *argv[]) {
  struct a *foo = make_new_a ();
  foo->x = 5;
}


скомпилируйте 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'а каждого класса.

> И что мы с такой информацией такого можем сделать?

пожалуйте изучить (ещё разок) примерчик из начала данного комментария. :)