Здравствуйте, _hum_, Вы писали: BFE>> Нет никакой проблемы в том, чтобы узнать во время выполнения, что данная функция вызвана из самой себя через последовательность других функций. __>вот здесь хотелось бы поподробнее (у вас 1000 разных функций, которые друг друга вызывают, и нужно определить, есть ли вариант зацикливания).
Я имел ввиду это:
void g()
{
f();
}
void f()
{
static bool b = false; // если f() - член класса, то b может/должна быть нестатическим членом классаif ( b )
{
// cyclereturn;
}
b = true; // RAII must be here
g();
b = false;
}
по сравнению с накладными расходами signal-slot это мелочь.
не вариант
Ещё, как вариант, можно завести глобальный map<void*, bool> g_stack в который добавлять, проверять и удалять на выходе флажок g_stack[this] = true ... false... Но это слишком накладно будет.
И каждый день — без права на ошибку...
Re[3]: "class const - метод" - можно ли организовать?
Здравствуйте, _hum_, Вы писали:
К>>1) через покрытие кода (мечты, мечты...) К>>2) через типы — например, на шаблонах (фактически, это то же покрытие кода) — гору кода переписать, либо выбрать другой язык (скалу) К>>3) через, внезапно, рантаймовые проверки.
__>да, 1) — наверное как раз то, что нужно было бы — обобщение подхода с const-спецификаторами.
Проблема в том, что компилятору нужно давать подсказки, чего ИМЕННО ты хочешь ограничить.
Семейство объектов может состоять из
— текущего объекта (через все мыслимые указатели на него)
— его агрегатов и связей (поддерево, наддерево), в т.ч. других типов — вопрос, где проходит граница владения?
— всех объектов данного класса в текущем потоке
— всех объектов данного класса во всех потоках, с учётом пинг-понга и отложенных вызовов через границы потока и очереди сообщений
Тупо зарубить все объекты данного класса — это, похоже, ты от отчаяния захотел.
__>2) — немного запутанный и, как мне показалось, все-таки не решающий проблемы с косвенными изменениями (как в исходном моем примере)
Очень даже решающий.
Прямой доступ по ссылкам/указателям — константность поверхностная, слишком опасно и легко снимается.
Заменяем на доступ через геттеры, с глубокой константностью.
Там, где функция внешняя, придётся её насильно параметризовать, — например, как я это показал
Если не нравятся шаблоны, можно ограничиться рефакторингом вот такого рода
class X {
X* xz_;
public:
// стандартный приём: делаем глубокую константность
X* xz() { return xz_; }
X const* xz() const { return xz_; }
};
template<class T> class deep_constness_ptr {
T* p_;
public:
T* get();
T const* get() const;
// и так далее, весь обвес класса-указателя
};
class X1 {
public:
deep_constness_ptr<X1> xz_;
};
// и теперь самое страшное!
//namespace GodNamespace // былоstruct GodContext { // сталоstatic X* x();
static X const* x() const; // дублируем все функции примитивного доступа
// либо заменяем обычные указатели на глубокие
deep_constness_ptr<X> y;
// и переписываем сложные функции - добавляя нужную константностьvoid bar();
void buz() const;
// на самый крайний случай, оставим себе право на шаблонtemplate<class GodContextWithOrWithoutConst>
static void foo(GodContextWithOrWithoutConst* myself) {
myself->x();
myself->y;
myself->foo();
myself->bar(); // где-то мы и по пальцам получим!
}
};
__>3) — это не подходит (уже обсуждалось ранее).
Но лучше иметь под рукой и такие проверки тоже.
Не все тесты и покрытия кода легко отобразить в систему типов. Можно — но иногда слишком мутно и дорого. Поэтому ассерты рулят.
Перекуём баги на фичи!
Re[2]: "class const - метод" - можно ли организовать?
Здравствуйте, SaZ, Вы писали:
SaZ>Соседняя ветка про Qt с топик стартером позволит более просто сформулировать хотелку автора.
SaZ>_hum_ хочет переложить написание логики приложения с разработчика на компилятор. Кто знаком с Qt, может почитать изначальный вопрос: http://rsdn.ru/forum/cpp.qt/6188183.flat#6188183
Ой, либо вы увидели нечто большее в моем том вопросе, либо все-таки не совсем поняли этот. Речь там и тут шла о несколько разных (с моей точки зрения) вещах — там — вопрос чисто технического характера — о нюансах связывания неконстантного слота в теле константного метода этого же класса, а здесь о возможности использования const-спецификатора для полной гарантии неизменности полей объекта, что, в частности, давало бы механизм предотвращения зацикливания.
Re[9]: "class const - метод" - можно ли организовать?
Здравствуйте, Ops, Вы писали:
BFE>>без использования шаблонных виртуальных методов, которых в С++ нет Ops>deleter у shared_ptr — это оно?
Не совсем. Для deleter'a есть "иерархия" из двух классов: базовый класс имеет виртуальную функцию, которая в шаблонном наследнике перекрыта. А сам shared_ptr хранит указатель на базовый класс, а не на производный класс (объект которого создаётся по new) — в результате мы имеем обычное динамическое связывание.
И каждый день — без права на ошибку...
Re[10]: "class const - метод" - можно ли организовать?
Здравствуйте, B0FEE664, Вы писали: BFE>Здравствуйте, _hum_, Вы писали: BFE>>> Нет никакой проблемы в том, чтобы узнать во время выполнения, что данная функция вызвана из самой себя через последовательность других функций. __>>вот здесь хотелось бы поподробнее (у вас 1000 разных функций, которые друг друга вызывают, и нужно определить, есть ли вариант зацикливания). BFE>Я имел ввиду это: BFE>
BFE>void g()
BFE>{
BFE> f();
BFE>}
BFE>void f()
BFE>{
BFE> static bool b = false; // если f() - член класса, то b может/должна быть нестатическим членом класса
BFE> if ( b )
BFE> {
BFE> // cycle
BFE> return;
BFE> }
BFE> b = true; // RAII must be here
BFE> g();
BFE> b = false;
BFE>}
BFE>
BFE>по сравнению с накладными расходами signal-slot это мелочь. BFE>
не вариант
BFE>Ещё, как вариант, можно завести глобальный map<void*, bool> g_stack в который добавлять, проверять и удалять на выходе флажок g_stack[this] = true ... false... Но это слишком накладно будет.
так это проверка на этапе выполнения (мы же с вами уже это обсуждали). а речь о том, как обнаружить циклы и дать себе по рукам на этапе компиляции.
Re[4]: "class const - метод" - можно ли организовать?
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, _hum_, Вы писали:
К>>>1) через покрытие кода (мечты, мечты...) К>>>2) через типы — например, на шаблонах (фактически, это то же покрытие кода) — гору кода переписать, либо выбрать другой язык (скалу) К>>>3) через, внезапно, рантаймовые проверки.
__>>да, 1) — наверное как раз то, что нужно было бы — обобщение подхода с const-спецификаторами.
К>Проблема в том, что компилятору нужно давать подсказки, чего ИМЕННО ты хочешь ограничить. К>Семейство объектов может состоять из К>- текущего объекта (через все мыслимые указатели на него) К>- его агрегатов и связей (поддерево, наддерево), в т.ч. других типов — вопрос, где проходит граница владения? К>- всех объектов данного класса в текущем потоке К>- всех объектов данного класса во всех потоках, с учётом пинг-понга и отложенных вызовов через границы потока и очереди сообщений
ну, так потому ваш вариант 1) мне и импонирует — в него в качестве параметров можно прописывать, неизменность какого множества объектов данного класса должна быть выдержана при вызове метода.
К>Тупо зарубить все объекты данного класса — это, похоже, ты от отчаяния захотел.
да. и отчасти потому, что 1) вроде как просто реализовать (но потом при разговоре с VTT выяснилось, что есть проблема с проверкой бинарных модулей); 2) вроде как имеет содержательное (а не техническое) значение (эдакий аналог static).
__>>2) — немного запутанный и, как мне показалось, все-таки не решающий проблемы с косвенными изменениями (как в исходном моем примере)
К>Очень даже решающий.
К>Прямой доступ по ссылкам/указателям — константность поверхностная, слишком опасно и легко снимается. К>Заменяем на доступ через геттеры, с глубокой константностью.
К>Там, где функция внешняя, придётся её насильно параметризовать, — например, как я это показал
К>Если не нравятся шаблоны, можно ограничиться рефакторингом вот такого рода К>
К>class X {
К> X* xz_;
К>public:
К> // стандартный приём: делаем глубокую константность
К> X* xz() { return xz_; }
К> X const* xz() const { return xz_; }
К>};
К>template<class T> class deep_constness_ptr {
К> T* p_;
К>public:
К> T* get();
К> T const* get() const;
К> // и так далее, весь обвес класса-указателя
К>};
К>class X1 {
К>public:
К> deep_constness_ptr<X1> xz_;
К>};
К>// и теперь самое страшное!
К>//namespace GodNamespace // было
К>struct GodContext { // стало
К> static X* x();
К> static X const* x() const; // дублируем все функции примитивного доступа
К> // либо заменяем обычные указатели на глубокие
К> deep_constness_ptr<X> y;
К> // и переписываем сложные функции - добавляя нужную константность
К> void bar();
К> void buz() const;
К> // на самый крайний случай, оставим себе право на шаблон
К> template<class GodContextWithOrWithoutConst>
К> static void foo(GodContextWithOrWithoutConst* myself) {
К> myself->x();
К> myself->y;
К> myself->foo();
К> myself->bar(); // где-то мы и по пальцам получим!
К> }
К>};
К>
ну, это еще страшнее смотрится. давайте лучше так — представим, что вы пишете class С_A из моего первого примера, а я пишу class С_B. и вот какой общий подход вы предлагаете, чтобы не дать возможности произойти модификации при вызове foo_A?
Re[5]: "class const - метод" - можно ли организовать?
Здравствуйте, _hum_, Вы писали:
__>ну, так потому ваш вариант 1) мне и импонирует — в него в качестве параметров можно прописывать, неизменность какого множества объектов данного класса должна быть выдержана при вызове метода.
Ага, "компилятор, сделай меня счастливым".
__>ну, это еще страшнее смотрится. давайте лучше так — представим, что вы пишете class С_A из моего первого примера, а я пишу class С_B. и вот какой общий подход вы предлагаете, чтобы не дать возможности произойти модификации при вызове foo_A?
Придётся любым способом вводить сущность "сессия".
Из CA::foo_A()const создаётся сессия, запрещающая изменять этот (или все) экземпляр CA.
В CA::set_x() допускается исключительно сессия, разрешающая изменять его.
А вот что бы мы делали, если бы у нас в языке не было const? Или если бы мы хотели более детально ограничивать права — например, x можно менять, а y нельзя?
Поэтому забудем про "компилятор, сделай меня счастливым".
Итак, способ номер раз. Хранить сессию прямо в объекте, — членами-флажками. Передача сессии осуществляется неявно, "состоянием реального мира".
С одной стороны, удобно — минимум писанины. С другой — есть риск чего-нибудь забыть. И с реентером проблемы.
Способ номер два: создавать объект сессии и передавать его: жетоны, куки, что угодно.
// не конкретизирую недраstruct Session;
bool allowed_to_set_x(Session);
bool allowed_to_set_y(Session);
class CA {
void set_x(Session s, int x) { assert(allowed_to_set_x(s); m_x = x; }
void foo() { m_pB->foo(make_session_with_all_permissions()); }
void bar() const { m_pB->bar(make_session_without_permissions()); }
// вид сессии можно и из константности выводить - ИНОГДА
Session make_typical_session() { return make_session_with_all_permissions(); }
Session make_typical_session() const { return make_session_without_permissions(); }
...
};
class CB {
void foo(Session s) { m_pA->set_x(s, 123); }
void bar(Session s) { m_pA->set_x(s, 456); } // если оно вызывается ТОЛЬКО из CA::bar()const, получим по пальцам
};
Это, безусловно, затратно, — но если мы один раз договорились, что внедряем сессии, — то дальше всё будет просто.
Самое главное, что мы сжигаем мосты и больше не позволяем бесконтрольно вызывать изменяющие методы. Если кто-то хочет сделать CA::set_x(), он должен получить откуда-то права. А точки выдачи прав — по пальцам сосчитать.
Это как private-секции, только рантайм.
Способ номер три. Просто заменить полиморфизм времени исполнения (проверку флажков в объекте сессии) на полиморфизм времени компиляции (семейство типов сессий и шаблоны).
Причём мы можем сколь угодно сложную информацию упаковывать — в mpl_vector, например.
Разница между "два" и "три" минимальная, — рефакторинг там в обе стороны почти бесплатно делается.
Наконец, ещё три способа.
Пусть CB хранит const CA*, то есть, исходно будет ограничен в правах. И только там, где CA ему явно разрешает поковыряться в себе, — пусть CA передаёт неконстантный указатель на себя.
Аналогично, если нужно интерфейс к CA урезАть по другим критериям, — например, разрешать доступ к тем или иным переменным, — тогда старые добрые интерфейсы решают. (По сути, С++ делает нам бесплатно два интерфейса у объекта — с константными и неконстантными членами. Но мы, вдохновившись, и руками можем написать интерфейсы, верно?)
Развитие этой темы — паттерн посетитель, — когда CA передаёт не прямо вот себя, а объект с функциями, которые можно дёргать.
И второе развитие — фабрика. Когда CB хранит не прямо CA, а некоторую заготовку, из которой можно получить временный указатель константного или неконстантного CA*. Ровно в соответствии с теми правами, которые указаны в жетоне сессии.
Это избавит от необходимости инструментировать все методы CA.
В качестве заготовки может послужить и сам const CA* — вот так:
class CA {
class Permitted {
private: Permitted() {} // чтоб неповадно былоfriend class CA;
};
void set_x(int x);
void set_y(int y);
CA* get_mutable_myself(Permitted) const { return const_cast<CA*>(this); }
void foo() { m_pA->foo(Permitted()); } // захотели и разрешилиvoid bar() const { m_pB->bar(); }
};
class CB {
CA const* m_pA;
void foo(CA::Permitted p) {
CA* pA = m_pA->get_mutable_myself(p); // реализовали право
pA->set_x(123);
pA->set_y(456);
};
void bar() {
// никак не взять неконстантный pA.
}
};
Перекуём баги на фичи!
Re[7]: "class const - метод" - можно ли организовать?
Здравствуйте, _hum_, Вы писали:
CS>>Не устраивает двумя моментами:
CS>>1. Возможность возникновения event/signal loop. Невозможность доказать статически отсутсвие таких циклов.
__>так а разве этим не грешат любые варианты организации двунаправленной связи между объектами?
А зачем там двунаправленный механизм?
CS>>2. Инфраструктура signal/slot занимает ресурсы. Как минимум память.
CS>>При условии наличия альтернативных механизмов свободных от 1 и 2 использование сигнал-слот представляется спорным.
__> а можно узнать об альтернативных механизмах, которые бы преодолевали эти два пункта, при том же самом функционале?
всякого рода event buses. Или как вариация оных bubbling events в browsers.
Используют тот факт что объекты уже находятся в дереве. Т.е. связь child parent уже есть.
Если child генерирует событие то это событие bubble up (здесь — всплывает) по цепочке от child ко всем его parent.
Таким образом если какому-то контейнеру нужно обработать событие от child он (контейнер) может это сделать без всякой подписки и механизма с ним ассоциированного. Плюс каждый parent может что-то добавить к событию или "потребить" (consume) его.
В Web events есть еще так называемая sinking или capturing фаза — http://catcode.com/domcontent/events/capture.html
Когда parents в иерархии получают события до детей. Т.е. в этой фазе parent может не пустить какое-то событие в child.
Т.е. механизм не требует вообще никакой доп. памяти и структур (кроме тех что уде наверняка есть типа parent child)
гибкий и мощный — позволяет разные event handling & delivering policy использовать.
принципиально свободен от проблемы циклов (loops).
Здравствуйте, c-smile, Вы писали:
CS>Здравствуйте, _hum_, Вы писали:
CS>>>Не устраивает двумя моментами:
CS>>>1. Возможность возникновения event/signal loop. Невозможность доказать статически отсутсвие таких циклов.
__>>так а разве этим не грешат любые варианты организации двунаправленной связи между объектами?
CS>А зачем там двунаправленный механизм?
ну, типичная задача — организация graphical user-interface для редактирования каких-то данных (модели данных) в варианте архитектуры "модель — представление".
для возможности редактирования нужна связь представление-> модель, для возможности оперативного отображения измененных данных (например, в нескольких представлениях), нужна связь модель->представление (для оповещение представлений, что данные модели изменились).
CS>>>2. Инфраструктура signal/slot занимает ресурсы. Как минимум память.
CS>>>При условии наличия альтернативных механизмов свободных от 1 и 2 использование сигнал-слот представляется спорным.
__>> а можно узнать об альтернативных механизмах, которые бы преодолевали эти два пункта, при том же самом функционале?
CS>всякого рода event buses. Или как вариация оных bubbling events в browsers.
CS>Используют тот факт что объекты уже находятся в дереве. Т.е. связь child parent уже есть.
CS>Если child генерирует событие то это событие bubble up (здесь — всплывает) по цепочке от child ко всем его parent. CS>Таким образом если какому-то контейнеру нужно обработать событие от child он (контейнер) может это сделать без всякой подписки и механизма с ним ассоциированного. Плюс каждый parent может что-то добавить к событию или "потребить" (consume) его.
CS>В Web events есть еще так называемая sinking или capturing фаза — http://catcode.com/domcontent/events/capture.html CS>Когда parents в иерархии получают события до детей. Т.е. в этой фазе parent может не пустить какое-то событие в child.
CS>Т.е. механизм CS> CS> не требует вообще никакой доп. памяти и структур (кроме тех что уде наверняка есть типа parent child) CS> гибкий и мощный — позволяет разные event handling & delivering policy использовать. CS> принципиально свободен от проблемы циклов (loops). CS>
и как этот механизм можно применить для решения указанной выше задачи организации архитектуры "модель-представление" в варианте, когда представлений несколько, и модель допускает редактирование через любое из них?
Re[6]: "class const - метод" - можно ли организовать?
Здравствуйте, Кодт.
Все это прекрасно, только вы всюду неявно налагаете на меня, пишущего класс C_B (помните, мы договорились — вы пишете класс С_A, а я C_B), ограничения на пользование классом C_A (то только обращение через сессии, то только через методы, возвращающие указатели на объекты C_A, то еще чего-то). А все договоренности ничего не стоят, ибо легко нарушаются (по забывчивости, невнимательности и т.п.). Я думал, вы предложите вариант, в котором я как создатель С_B ВЫНУЖДЕН буду делать так, как вам надо, ибо в противном случае буду получать некомпилирующийся код.
Re[7]: "class const - метод" - можно ли организовать?
Здравствуйте, _hum_, Вы писали:
__>Все это прекрасно, только вы всюду неявно налагаете на меня, пишущего класс C_B (помните, мы договорились — вы пишете класс С_A, а я C_B), ограничения на пользование классом C_A (то только обращение через сессии, то только через методы, возвращающие указатели на объекты C_A, то еще чего-то). А все договоренности ничего не стоят, ибо легко нарушаются (по забывчивости, невнимательности и т.п.). Я думал, вы предложите вариант, в котором я как создатель С_B ВЫНУЖДЕН буду делать так, как вам надо, ибо в противном случае буду получать некомпилирующийся код.
Если я написал класс, у которого в интерфейсе все ключевые функции требуют сессию, а конструктор сессии приватный, — то все клиенты будут вынуждены делать так, как мне надо. Иначе код будет некомпилирующийся, по причине несоответствующих сигнатур функций.
Писанины, конечно, при этом прибавится — синтаксический шум в виде этих самых идентификаторов сессий, либо в виде обёрток (классов и замыканий) над кодом-внутри-сессии.
Перекуём баги на фичи!
Re[8]: "class const - метод" - можно ли организовать?
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, _hum_, Вы писали:
__>>Все это прекрасно, только вы всюду неявно налагаете на меня, пишущего класс C_B (помните, мы договорились — вы пишете класс С_A, а я C_B), ограничения на пользование классом C_A (то только обращение через сессии, то только через методы, возвращающие указатели на объекты C_A, то еще чего-то). А все договоренности ничего не стоят, ибо легко нарушаются (по забывчивости, невнимательности и т.п.). Я думал, вы предложите вариант, в котором я как создатель С_B ВЫНУЖДЕН буду делать так, как вам надо, ибо в противном случае буду получать некомпилирующийся код.
К>Если я написал класс, у которого в интерфейсе все ключевые функции требуют сессию, а конструктор сессии приватный, — то все клиенты будут вынуждены делать так, как мне надо. Иначе код будет некомпилирующийся, по причине несоответствующих сигнатур функций. К>Писанины, конечно, при этом прибавится — синтаксический шум в виде этих самых идентификаторов сессий, либо в виде обёрток (классов и замыканий) над кодом-внутри-сессии.
ну, вот я беру ваш код К>Способ номер два: создавать объект сессии и передавать его: жетоны, куки, что угодно. К>
К>// не конкретизирую недра
К>struct Session;
К>bool allowed_to_set_x(Session);
К>bool allowed_to_set_y(Session);
К>class CA {
К> void set_x(Session s, int x) { assert(allowed_to_set_x(s); m_x = x; }
К> void foo() { m_pB->foo(make_session_with_all_permissions()); }
К> void bar() const { m_pB->bar(make_session_without_permissions()); }
К> // вид сессии можно и из константности выводить - ИНОГДА
К> Session make_typical_session() { return make_session_with_all_permissions(); }
К> Session make_typical_session() const { return make_session_without_permissions(); }
К> ...
К>};
К>class CB {
К> void foo(Session s) { m_pA->set_x(s, 123); }
К> void bar(Session s) { m_pA->set_x(s, 456); } // если оно вызывается ТОЛЬКО из CA::bar()const, получим по пальцам
К>};
К>
и просто видоизменяю наподобие:
class CB {
C_A* m_pA;
...
void foo(Session s) { m_pA->set_x(s, 123); }
//void bar(Session s) { m_pA->set_x(s, 456); } // если оно вызывается ТОЛЬКО из CA::bar()const, получим по пальцамvoid bar(Session s)
{
const Session SessionWithAllPermissions = m_pA->make_typical_session(); // поскольку m_pA есть неконтсантный указатель C_A*, то все ок - я получу сессию со всеми разрешениями на модификацию
m_pA->set_x(SessionWithAllPermissions, 456); // опять же, поскольку сессия все разрешает, то могу модифицировать
}
};
ну и? вызов CA::bar()const опять станет модифицирующим, и компилятор это проглотит.
Re[9]: "class const - метод" - можно ли организовать?
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, _hum_, Вы писали:
__>>ну, вот я беру ваш код __>>и просто видоизменяю наподобие:
К>А фигушки, если CA::make_typical_session приватный. Он не предназначен для того, чтобы посторонние его вызывали.
извиняюсь, а как тогда вообще можно установить новое значение C_A::m_x за пределами области видимости C_A и его наследников?
К>Этак и со старой доброй константностью можно было проворачивать читерство: К>
К>const CA* pA;
К>....
К>const_cast<CA*>(pA)->set_x(123); // эй компилятор, почему ты не дал мне здесь по пальцам?!
К>
нет, тут совсем другая ситуация — здесь в явном виде говорится — я сознательно нарушаю требования константности, и отвечаю за последствия.
а всюду выше речь велась о защите от нечаянной непредумышленной модификации.
Re[11]: "class const - метод" - можно ли организовать?
Здравствуйте, _hum_, Вы писали:
__>извиняюсь, а как тогда вообще можно установить новое значение C_A::m_x за пределами области видимости C_A и его наследников?
Ну как: войти в сессию, получить у компетентной стороны токен, с этим токеном пойти и вызвать метод-модификатор.
Сам же хотел обеспечить разграничение прав? Вот оно так и делается.
Дальше нюансы — насколько система типов позволяет уменьшить синтаксический шум.
И насколько компилятор способен покрытие кода отследить (либо мы сваливаем всё в рантайм, не доверяя и не нагружая компилятор, либо тащим всё в строгие типы и получаем дополнительный синтаксический шум и дополнительное время компиляции).
Перекуём баги на фичи!
Re[12]: "class const - метод" - можно ли организовать?
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, _hum_, Вы писали:
__>>извиняюсь, а как тогда вообще можно установить новое значение C_A::m_x за пределами области видимости C_A и его наследников?
К>Ну как: войти в сессию, получить у компетентной стороны токен, с этим токеном пойти и вызвать метод-модификатор.
так что мешает получить у "компетентной стороны" сессию, а потом использовать ее не по назначению?
К>Сам же хотел обеспечить разграничение прав? Вот оно так и делается.
да, но ваше решение все равно не спасает от "выстрела в ногу"
Re[13]: "class const - метод" - можно ли организовать?
Здравствуйте, _hum_, Вы писали:
__>так что мешает получить у "компетентной стороны" сессию, а потом использовать ее не по назначению?
Например, отсутствие публичного конструктора копирования. Передавать сессию только по ссылке.
А для любителей стрельбы по ногам — добавить в экземпляр сессии рантаймовую информацию, и обложить её ассертами.
__>да, но ваше решение все равно не спасает от "выстрела в ногу"
Если очень сильно захотеть, то в ногу можно на любом языке программирования выстрелить. Даже на супер-пупер-типизированном, вроде хаскелла и идриса. И на супер-пупер-обложенном проверками, вроде эйфеля и ады.
(Например, вставить код вида
и всё, автоматизированное покрытие кода — коту под хвост. список проблем — мне больше всего гипотеза Коллатца нравится).
Фантомный тип "с константностью" защищает от большого класса простых ошибок.
Фантом "nullable" и "non-null" — ещё от одного класса. (Это уже C#).
Другие фантомы требуют писанины. Даже на хаскелле и аде.
Суть приёма в том, что у нас есть слой пассивных типов, над которыми можно делать всё, что угодно (включая set_x), есть слой-изолятор, запрещающий работать с ними напрямую, и слой фантомных типов — обёрток над пассивными, в котором реализована логика разрешений.
Минимальные изменения в исходный код — это добавить токены сессий (фантом над void, фактически).
Мы как бы домысливаем, что все функции foo(T,U,V), set_x(int) и т.п. — имеют ещё один пустой аргумент — foo(T,U,V,void), set_x(int,void) — а затем заменяем void на фантом.
Крупные изменения — сделать фантомы над самими объектами. Собственно, как я уже сказал, квалификатор const — это оно. Но в данном случае его оказалось недостаточно, слишком уж тупая логика у компилятора.
Отчасти это административная мера. То есть, надо себя заставить хотя бы начать так писать.
И конечно, это не спасёт нас от читерства, если мы пойдём на такое читерство намеренно. Но, поскольку случайное читерство невозможно, это всегда ещё большая писанина, — то это спасает нас от ошибок.