Re[9]: "class const - метод" - можно ли организовать?
От: B0FEE664  
Дата: 24.09.15 16:23
Оценка:
Здравствуйте, _hum_, Вы писали:

BFE>> Нет никакой проблемы в том, чтобы узнать во время выполнения, что данная функция вызвана из самой себя через последовательность других функций.


__>вот здесь хотелось бы поподробнее (у вас 1000 разных функций, которые друг друга вызывают, и нужно определить, есть ли вариант зацикливания).


Я имел ввиду это:

void g()
{
   f();
}

void f()
{
  static bool b = false; // если f() - член класса, то b может/должна быть нестатическим членом класса
  if ( b )
  {
    // cycle
    return;
  } 
  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 - метод" - можно ли организовать?
От: Кодт Россия  
Дата: 24.09.15 16:23
Оценка:
Здравствуйте, _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 - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 24.09.15 16:42
Оценка:
Здравствуйте, SaZ, Вы писали:

SaZ>Соседняя ветка про Qt с топик стартером позволит более просто сформулировать хотелку автора.


SaZ>_hum_ хочет переложить написание логики приложения с разработчика на компилятор. Кто знаком с Qt, может почитать изначальный вопрос: http://rsdn.ru/forum/cpp.qt/6188183.flat#6188183
Автор: _hum_
Дата: 20.09.15


Ой, либо вы увидели нечто большее в моем том вопросе, либо все-таки не совсем поняли этот. Речь там и тут шла о несколько разных (с моей точки зрения) вещах — там — вопрос чисто технического характера — о нюансах связывания неконстантного слота в теле константного метода этого же класса, а здесь о возможности использования const-спецификатора для полной гарантии неизменности полей объекта, что, в частности, давало бы механизм предотвращения зацикливания.
Re[9]: "class const - метод" - можно ли организовать?
От: B0FEE664  
Дата: 24.09.15 16:57
Оценка:
Здравствуйте, Ops, Вы писали:

BFE>>без использования шаблонных виртуальных методов, которых в С++ нет

Ops>deleter у shared_ptr — это оно?

Не совсем. Для deleter'a есть "иерархия" из двух классов: базовый класс имеет виртуальную функцию, которая в шаблонном наследнике перекрыта. А сам shared_ptr хранит указатель на базовый класс, а не на производный класс (объект которого создаётся по new) — в результате мы имеем обычное динамическое связывание.
И каждый день — без права на ошибку...
Re[10]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 24.09.15 18:25
Оценка:
Здравствуйте, 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_ Беларусь  
Дата: 24.09.15 18:40
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, _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 - метод" - можно ли организовать?
От: Кодт Россия  
Дата: 24.09.15 21:23
Оценка:
Здравствуйте, _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::foo() { m_pB->foo(this); }
CA::bar() const { m_pB->bar(); }

CB::foo(CA* pA) { assert(pA == m_pA); pA->set_x(123); }
CB::bar() { m_pB->get_x(); }

Аналогично, если нужно интерфейс к 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 - метод" - можно ли организовать?
От: c-smile Канада http://terrainformatica.com
Дата: 24.09.15 23:25
Оценка:
Здравствуйте, _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.

Т.е. механизм
  1. не требует вообще никакой доп. памяти и структур (кроме тех что уде наверняка есть типа parent child)
  2. гибкий и мощный — позволяет разные event handling & delivering policy использовать.
  3. принципиально свободен от проблемы циклов (loops).
Отредактировано 24.09.2015 23:31 c-smile . Предыдущая версия .
Re[8]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 28.09.15 10:29
Оценка:
Здравствуйте, 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>
  1. не требует вообще никакой доп. памяти и структур (кроме тех что уде наверняка есть типа parent child)
    CS>
  2. гибкий и мощный — позволяет разные event handling & delivering policy использовать.
    CS>
  3. принципиально свободен от проблемы циклов (loops).
    CS>

и как этот механизм можно применить для решения указанной выше задачи организации архитектуры "модель-представление" в варианте, когда представлений несколько, и модель допускает редактирование через любое из них?
Re[6]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 28.09.15 10:42
Оценка:
Здравствуйте, Кодт.
Все это прекрасно, только вы всюду неявно налагаете на меня, пишущего класс C_B (помните, мы договорились — вы пишете класс С_A, а я C_B), ограничения на пользование классом C_A (то только обращение через сессии, то только через методы, возвращающие указатели на объекты C_A, то еще чего-то). А все договоренности ничего не стоят, ибо легко нарушаются (по забывчивости, невнимательности и т.п.). Я думал, вы предложите вариант, в котором я как создатель С_B ВЫНУЖДЕН буду делать так, как вам надо, ибо в противном случае буду получать некомпилирующийся код.
Re[7]: "class const - метод" - можно ли организовать?
От: Кодт Россия  
Дата: 28.09.15 13:09
Оценка:
Здравствуйте, _hum_, Вы писали:

__>Все это прекрасно, только вы всюду неявно налагаете на меня, пишущего класс C_B (помните, мы договорились — вы пишете класс С_A, а я C_B), ограничения на пользование классом C_A (то только обращение через сессии, то только через методы, возвращающие указатели на объекты C_A, то еще чего-то). А все договоренности ничего не стоят, ибо легко нарушаются (по забывчивости, невнимательности и т.п.). Я думал, вы предложите вариант, в котором я как создатель С_B ВЫНУЖДЕН буду делать так, как вам надо, ибо в противном случае буду получать некомпилирующийся код.


Если я написал класс, у которого в интерфейсе все ключевые функции требуют сессию, а конструктор сессии приватный, — то все клиенты будут вынуждены делать так, как мне надо. Иначе код будет некомпилирующийся, по причине несоответствующих сигнатур функций.
Писанины, конечно, при этом прибавится — синтаксический шум в виде этих самых идентификаторов сессий, либо в виде обёрток (классов и замыканий) над кодом-внутри-сессии.
Перекуём баги на фичи!
Re[8]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 28.09.15 13:50
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, _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 - метод" - можно ли организовать?
От: Кодт Россия  
Дата: 28.09.15 14:14
Оценка:
Здравствуйте, _hum_, Вы писали:

__>ну, вот я беру ваш код

__>и просто видоизменяю наподобие:

А фигушки, если CA::make_typical_session приватный. Он не предназначен для того, чтобы посторонние его вызывали.

Этак и со старой доброй константностью можно было проворачивать читерство:
const CA* pA;
....
const_cast<CA*>(pA)->set_x(123); // эй компилятор, почему ты не дал мне здесь по пальцам?!
Перекуём баги на фичи!
Re[10]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 28.09.15 14:26
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, _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 - метод" - можно ли организовать?
От: Кодт Россия  
Дата: 29.09.15 07:53
Оценка:
Здравствуйте, _hum_, Вы писали:

__>извиняюсь, а как тогда вообще можно установить новое значение C_A::m_x за пределами области видимости C_A и его наследников?


Ну как: войти в сессию, получить у компетентной стороны токен, с этим токеном пойти и вызвать метод-модификатор.

Сам же хотел обеспечить разграничение прав? Вот оно так и делается.
Дальше нюансы — насколько система типов позволяет уменьшить синтаксический шум.
И насколько компилятор способен покрытие кода отследить (либо мы сваливаем всё в рантайм, не доверяя и не нагружая компилятор, либо тащим всё в строгие типы и получаем дополнительный синтаксический шум и дополнительное время компиляции).
Перекуём баги на фичи!
Re[12]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 29.09.15 11:25
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, _hum_, Вы писали:


__>>извиняюсь, а как тогда вообще можно установить новое значение C_A::m_x за пределами области видимости C_A и его наследников?


К>Ну как: войти в сессию, получить у компетентной стороны токен, с этим токеном пойти и вызвать метод-модификатор.


так что мешает получить у "компетентной стороны" сессию, а потом использовать ее не по назначению?

К>Сам же хотел обеспечить разграничение прав? Вот оно так и делается.


да, но ваше решение все равно не спасает от "выстрела в ногу"
Re[13]: "class const - метод" - можно ли организовать?
От: Кодт Россия  
Дата: 29.09.15 14:25
Оценка:
Здравствуйте, _hum_, Вы писали:

__>так что мешает получить у "компетентной стороны" сессию, а потом использовать ее не по назначению?


Например, отсутствие публичного конструктора копирования. Передавать сессию только по ссылке.
А для любителей стрельбы по ногам — добавить в экземпляр сессии рантаймовую информацию, и обложить её ассертами.

__>да, но ваше решение все равно не спасает от "выстрела в ногу"


Если очень сильно захотеть, то в ногу можно на любом языке программирования выстрелить. Даже на супер-пупер-типизированном, вроде хаскелла и идриса. И на супер-пупер-обложенном проверками, вроде эйфеля и ады.
(Например, вставить код вида
if(Great_Unresolved_Problem_Is_True()) { ..... } else { ..... }

и всё, автоматизированное покрытие кода — коту под хвост. список проблем — мне больше всего гипотеза Коллатца нравится).

Фантомный тип "с константностью" защищает от большого класса простых ошибок.
Фантом "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 — это оно. Но в данном случае его оказалось недостаточно, слишком уж тупая логика у компилятора.

Отчасти это административная мера. То есть, надо себя заставить хотя бы начать так писать.

И конечно, это не спасёт нас от читерства, если мы пойдём на такое читерство намеренно. Но, поскольку случайное читерство невозможно, это всегда ещё большая писанина, — то это спасает нас от ошибок.
Перекуём баги на фичи!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.