"class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 23.09.15 10:20
Оценка:
Доброго дня.
Раньше как-то сильно не задумывался и негласно для себя считал, что const-спецификатор метода гарантирует неизменность полей объекта, из которого этот метод вызывается. А вот когда начал работать с сигнал-слот-архитектурой, увидел, что это, вообще говоря, не так:

class C_B;

////////////////////////////
////       C_A          ////
////////////////////////////
class C_A
{
    C_B* m_pB;

    int  m_x;
public:
    //------------------------------------------
    void set_pB(C_B* pB){m_pB = pB;}
    //------------------------------------------
    void set_x(int x)   {m_x = x;}
    //------------------------------------------
    void foo_A(void)const;// несмотря на const, вызов этой функции может изменить значение поля m_x
    //------------------------------------------
};
////////////////////////////

////////////////////////////
////       C_B          ////
////////////////////////////
class C_B
{
    C_A* m_pA;
public:
    //------------------------------------------
    C_B(C_A* pA):m_pA(pA){}
    //------------------------------------------
    void foo_B(void){ m_pA->set_x(10);}
    //------------------------------------------
};
////////////////////////////

//------------------------------------------
void C_A::foo_A(void)const
{
    m_pB->foo_B();
}
//------------------------------------------



void main(void) 
{
    C_A A;
    C_B B(&A);

    A.set_pB(&B);

    A.set_x(0);
    A.foo_A();
}


Потому встал вопрос, есть ли в других языках или в новом стандарте с++ что-нибудь наподобие "class const — метода", который делает
константными ЛЮБЫЕ this данного класса в своей области видимости, и тем самым предотвращает всякое изменение любого (а значит и заданного)объекта данного класса?

Это понадобилось, в частности, для того, чтобы на этапе компиляции отлавливать зацикливания. Например,
если foo_A воспринимаеть как сигнал о модификации объекта, к которому приконнекчен слот foo_B, то хотелось бы иметь гарантиии, что вызов этого слота ен приведет к повторному изменению объекта и повторному вызову сигнала (тем самым входя в цикл).
Re: "class const - метод" - можно ли организовать?
От: VTT http://vtt.to
Дата: 23.09.15 10:30
Оценка:
У вас тут const-ность нарушается из-за наличия в классе не const ссылки на самого себя. Этот пример можно упростить до
class
t_Something
{
  protected: t_Something * m_p_non_const;
  protected: int           m_x = 0;
    
  public:
  t_Something(void)
  :  m_p_non_const(this)
  {
    // do nothing;
  }
    
  public: void
  Set_X(int const x) const
  {
    m_p_non_const->m_x = x;
  }
};

int
main(void)
{
  t_Something const something;
  something.Set_X(42);
}


Если хочется гарантий, то можно делать immutable объекты.
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Отредактировано 23.09.2015 10:37 VTT . Предыдущая версия . Еще …
Отредактировано 23.09.2015 10:36 VTT . Предыдущая версия .
Re: "class const - метод" - можно ли организовать?
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 23.09.15 10:56
Оценка:
Здравствуйте, _hum_, Вы писали:

__> Раньше как-то сильно не задумывался и негласно для себя считал, что const-спецификатор метода гарантирует неизменность полей объекта, из которого этот метод вызывается.


Я, как сишник, для себя считаю, что const-спецификатор есть в первую очередь указание оптимизатору, что некоторый регион памяти не изменяется в течение жизни указателя. И если он изменяется по какой-то причине, то получаем UB. Истина математика всегда делать самые слабые утверждения А как оно в стандарте

Реализовать твоё поведение вряд ли возможно в принципе. Потому как на каждую операцию записи нам необходимо доказать, что невозможно изменение содержимого любого константного указателя. Что нетривиально.
Re[2]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 23.09.15 11:04
Оценка:
Здравствуйте, VTT, Вы писали:

VTT>У вас тут const-ность нарушается из-за наличия в классе не const ссылки на самого себя. Этот пример можно упростить до

VTT>
VTT>class
VTT>t_Something
VTT>{
VTT>  protected: t_Something * m_p_non_const;
VTT>  protected: int           m_x = 0;
    
VTT>  public:
VTT>  t_Something(void)
VTT>  :  m_p_non_const(this)
VTT>  {
VTT>    // do nothing;
VTT>  }
    
VTT>  public: void
VTT>  Set_X(int const x) const
VTT>  {
VTT>    m_p_non_const->m_x = x;
VTT>  }
VTT>};

VTT>int
VTT>main(void)
VTT>{
VTT>  t_Something const something;
VTT>  something.Set_X(42);
VTT>}
VTT>


да, спасибо, так нагляднее.

VTT>Если хочется гарантий, то можно делать immutable объекты.


вы не совсем тогда поняли — я хочу гарантию, что ВЫЗОВ ДАННОГО МЕТОДА не приведет к изменению данных, а не что эти данные ВОВСЕ не должны меняться.
и реализация этого вроде бы не сложная — компилятор должен все this-указатели данного класса, которые попадают в область видимости данного метода, считать const this. тогда бы он смог выдать ошибку в вашем примере, типа:
"m_p_non_const->m_x = x : использование неконстантного указателя на класс t_Something внутри class const метода"
Re[2]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 23.09.15 11:08
Оценка:
Здравствуйте, Mystic, Вы писали:

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


__>> Раньше как-то сильно не задумывался и негласно для себя считал, что const-спецификатор метода гарантирует неизменность полей объекта, из которого этот метод вызывается.


M>Я, как сишник, для себя считаю, что const-спецификатор есть в первую очередь указание оптимизатору, что некоторый регион памяти не изменяется в течение жизни указателя. И если он изменяется по какой-то причине, то получаем UB. Истина математика всегда делать самые слабые утверждения А как оно в стандарте


так одно другого не исключает мы говорим компилятору (который включает в себя и синтаксический анализатор, и оптимизатор), как мы считаем, должен себя вести объект, а уже компилятор использует эту инфу для многих целей — и для отлавливания семантических ошибок (сказали, что будем использовать без изменения, и почему-то пишем изменяющий код) и для оптимизации.

M>Реализовать твоё поведение вряд ли возможно в принципе. Потому как на каждую операцию записи нам необходимо доказать, что невозможно изменение содержимого любого константного указателя. Что нетривиально.


вроде бы несложно (см. пост выше для VTT)
Re[3]: "class const - метод" - можно ли организовать?
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 23.09.15 11:10
Оценка:
Здравствуйте, _hum_, Вы писали:


__>вы не совсем тогда поняли — я хочу гарантию, что ВЫЗОВ ДАННОГО МЕТОДА не приведет к изменению данных, а не что эти данные ВОВСЕ не должны меняться.

__>и реализация этого вроде бы не сложная — компилятор должен все this-указатели данного класса, которые попадают в область видимости данного метода, считать const this. тогда бы он смог выдать ошибку в вашем примере, типа:
__>"m_p_non_const->m_x = x : использование неконстантного указателя на класс t_Something внутри class const метода"

Это может быть и некоторый другой класс, откуда компилятору знать, куда будет указывать m_p_non_const в момент вызова метода?
Re[4]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 23.09.15 11:18
Оценка:
Здравствуйте, Mystic, Вы писали:

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



__>>вы не совсем тогда поняли — я хочу гарантию, что ВЫЗОВ ДАННОГО МЕТОДА не приведет к изменению данных, а не что эти данные ВОВСЕ не должны меняться.

__>>и реализация этого вроде бы не сложная — компилятор должен все this-указатели данного класса, которые попадают в область видимости данного метода, считать const this. тогда бы он смог выдать ошибку в вашем примере, типа:
__>>"m_p_non_const->m_x = x : использование неконстантного указателя на класс t_Something внутри class const метода"

M>Это может быть и некоторый другой класс, откуда компилятору знать, куда будет указывать m_p_non_const в момент вызова метода?


неважно, куда будет указывать. главное, какого он типа. а это определяется на этапе компиляции.
(речь не о динамических отлавливаниях изменений, когда, действительно, требуется рантайм-анализ указателей, а о статическом — мы просто тупо запрещаем в коде, попадающем в область видимости данного метода, менять что-то через указатели данного класса)
Re[3]: "class const - метод" - можно ли организовать?
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 23.09.15 11:21
Оценка:
Здравствуйте, _hum_, Вы писали:

__>вроде бы несложно (см. пост выше для VTT)


Например?


struct X 
{ 
    X * next; 
    void f() const { next->next = nullptr; }
};

void something(X * x);

int main()
{
    X x;
    something(&x); // Какими будут поля структуры X после выхода из метода?
    x.f(); // Как понять, есть нарушение или нет?
    return 0;
}

#ifdef UB
    void something(X * x)
    {
        x->next = x;
    }
#else
    void something(X * x)
    {
        x->next = new X();
    }
#endif
Re[5]: "class const - метод" - можно ли организовать?
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 23.09.15 11:23
Оценка:
Здравствуйте, _hum_, Вы писали:

__>неважно, куда будет указывать. главное, какого он типа. а это определяется на этапе компиляции.

__>(речь не о динамических отлавливаниях изменений, когда, действительно, требуется рантайм-анализ указателей, а о статическом — мы просто тупо запрещаем в коде, попадающем в область видимости данного метода, менять что-то через указатели данного класса)

Т. е. ты хочешь, чтобы некоторый superconst влиял на все экземпляры данного класса?
Re[5]: "class const - метод" - можно ли организовать?
От: VTT http://vtt.to
Дата: 23.09.15 11:23
Оценка:
Здравствуйте, _hum_, Вы писали:

__>(речь не о динамических отлавливаниях изменений, когда, действительно, требуется рантайм-анализ указателей, а о статическом — мы просто тупо запрещаем в коде, попадающем в область видимости данного метода, менять что-то через указатели данного класса)


Ну можно попробовать использовать не указатели, а специальный reference_wrapper класс, который бы давал доступ к изменяемому объекту только если он сам не const.
т.е. имел бы два метода (в отличие от стандартного)
T & get();
T const & get() const;
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Re[6]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 23.09.15 11:26
Оценка:
Здравствуйте, Mystic, Вы писали:

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


__>>неважно, куда будет указывать. главное, какого он типа. а это определяется на этапе компиляции.

__>>(речь не о динамических отлавливаниях изменений, когда, действительно, требуется рантайм-анализ указателей, а о статическом — мы просто тупо запрещаем в коде, попадающем в область видимости данного метода, менять что-то через указатели данного класса)

M>Т. е. ты хочешь, чтобы некоторый superconst влиял на все экземпляры данного класса?


ну, можно и так сказать (только не на сами экземпляры, а на указатели на эти экземпляры, и не на все указатели, а на те, что по коду попадают в область видимости данного superconst- метода)
Re[4]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 23.09.15 11:32
Оценка:
Здравствуйте, Mystic, Вы писали:

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


__>>вроде бы несложно (см. пост выше для VTT)


M>Например?


M>

M>struct X 
M>{ 
M>    X * next; 
M>    void f() const { next->next = nullptr; }
M>};

M>void something(X * x);

M>int main()
M>{
M>    X x;
M>    something(&x); // Какими будут поля структуры X после выхода из метода?
M>    x.f(); // Как понять, есть нарушение или нет?
M>    return 0;
M>}

M>#ifdef UB
M>    void something(X * x)
M>    {
        x->>next = x;
M>    }
M>#else
M>    void something(X * x)
M>    {
        x->>next = new X();
M>    }
M>#endif

M>

если под
void f() const { next->next = nullptr; }

понималось
void f() class_const { next->next = nullptr; }

то компилятор уже в этом месте не пропустит, ибо у вас в области видимости class_const-метода осуществляется изменение через указатель на данный класс.
иными словами, компилятор трактует это как:
void f() class_const { (const X*)next->next = nullptr; }

и резонно выдает ошибку.
Re: "class const - метод" - можно ли организовать?
От: Mr.Delphist  
Дата: 23.09.15 11:38
Оценка:
Здравствуйте, _hum_, Вы писали:

__> Доброго дня.

__> Раньше как-то сильно не задумывался и негласно для себя считал, что const-спецификатор метода гарантирует неизменность полей объекта, из которого этот метод вызывается. А вот когда начал работать с сигнал-слот-архитектурой, увидел, что это, вообще говоря, не так:

Авторы не захотели прописать mutable напротив поля m_x (или закладывались на какие-то компиляторы без поддержки оного), вот и делается такой "хак себя", когда весь класс неизменный, но определённое поле — эдакая temp-переменная, вроде как захваченная в контекст.

Собственно, ничего нового в явлении нет, идиома известна ещё со времён plain C, равно как и грабли ей сопутствующие http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule
Re[6]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 23.09.15 11:41
Оценка:
Здравствуйте, VTT, Вы писали:

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


__>>(речь не о динамических отлавливаниях изменений, когда, действительно, требуется рантайм-анализ указателей, а о статическом — мы просто тупо запрещаем в коде, попадающем в область видимости данного метода, менять что-то через указатели данного класса)


VTT>Ну можно попробовать использовать не указатели, а специальный reference_wrapper класс, который бы давал доступ к изменяемому объекту только если он сам не const.

VTT>т.е. имел бы два метода (в отличие от стандартного)
VTT>
VTT>T & get();
VTT>T const & get() const;
VTT>

а разве это может спасти от ситуации с моим первым примером, когда C_B не использует (ибо его никто не может обязать это делать) такой враппер для хранения ссылки на объект C_A?
Re[2]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 23.09.15 11:45
Оценка:
Здравствуйте, Mr.Delphist, Вы писали:

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


__>> Доброго дня.

__>> Раньше как-то сильно не задумывался и негласно для себя считал, что const-спецификатор метода гарантирует неизменность полей объекта, из которого этот метод вызывается. А вот когда начал работать с сигнал-слот-архитектурой, увидел, что это, вообще говоря, не так:

MD>Авторы не захотели прописать mutable напротив поля m_x (или закладывались на какие-то компиляторы без поддержки оного), вот и делается такой "хак себя", когда весь класс неизменный, но определённое поле — эдакая temp-переменная, вроде как захваченная в контекст.


MD>Собственно, ничего нового в явлении нет, идиома известна ещё со времён plain C, равно как и грабли ей сопутствующие http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule


не совсем понял, о чем вы. мютабельность полей тут не при чем.
Re[7]: "class const - метод" - можно ли организовать?
От: VTT http://vtt.to
Дата: 23.09.15 11:50
Оценка:
Ну если уж вы часть программы не контролируете, то никакой superconst тут не поможет.
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Re[8]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 23.09.15 12:00
Оценка:
Здравствуйте, VTT, Вы писали:

VTT>Ну если уж вы часть программы не контролируете, то никакой superconst тут не поможет.


нет, речь о другом — в самом классе C_A я могу проконтролировать, чтобы все указатели на себя использовались только через такие врапперы, но за пределами этого класса — нет. и глупо рассчитывать на то, что использовать объекты этого класса будут только через врапперы (ну разве только специально писать инструкцию пользования данным классом, что довольно дико).
а компилятор мог бы это автоматом все отслеживать и говорить, где что не так...
Re[9]: "class const - метод" - можно ли организовать?
От: VTT http://vtt.to
Дата: 23.09.15 12:10
Оценка:
Здравствуйте, _hum_, Вы писали:

__>а компилятор мог бы это автоматом все отслеживать и говорить, где что не так...


И как бы он мог это отслеживать? Информации о том, указывает ли указатель в классе C_B на тот же экземпляр класса C_A, что и this в методе foo_A у него в принципе нет. В приведенном примере это очевидно только из-за крайнего упрощения.
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Re[10]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 23.09.15 12:29
Оценка:
Здравствуйте, VTT, Вы писали:

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


__>>а компилятор мог бы это автоматом все отслеживать и говорить, где что не так...


VTT>И как бы он мог это отслеживать? Информации о том, указывает ли указатель в классе C_B на тот же экземпляр класса C_A, что и this в методе foo_A у него в принципе нет. В приведенном примере это очевидно только из-за крайнего упрощения.


нет. и вы тоже не поняли значит. речь не о том, чтобы не модифицировать ЗАДАННЫЙ ЭКЗЕМПЛЯР, а о том, чтобы запретить модификацию ВСЕ ЭКЗЕМПЛЯРЫ, если код их модификации попадает "в нитку", которая запускается вызовом class_const-метода.

иными словами компилятор должен действовать так:

0) заводит стек функций
1) помещает в стек class_const-метод
2) пока стек не пуст, берет верхний элемент стека и для него анализирует тело функции:
2.1) все указатели типа C_A* трактует как const C_A* и выдает ошибку, если с помощью них производится попытка модификации;
2.2) если встретилась функция, то помещает в стек и переходит к 2);
2.3) делает pop для стека.
3) анализ завершен

(тут еще оговорки, конечно, для рекурсивных вызовов, но это тоже решаемо на этапе анализа — просто не надо добавлять в стек то, что уже раньше встречалось)
Re[11]: "class const - метод" - можно ли организовать?
От: VTT http://vtt.to
Дата: 23.09.15 12:39
Оценка:
Здравствуйте, _hum_, Вы писали:

__>нет. и вы тоже не поняли значит. речь не о том, чтобы не модифицировать ЗАДАННЫЙ ЭКЗЕМПЛЯР, а о том, чтобы запретить модификацию ВСЕ ЭКЗЕМПЛЯРЫ, если код их модификации попадает "в нитку", которая запускается вызовом class_const-метода.


__>иными словами компилятор должен действовать так:


__>0) заводит стек функций

__>1) помещает в стек class_const-метод
__>2) пока стек не пуст, берет верхний элемент стека и для него анализирует тело функции:
__> 2.1) все указатели типа C_A* трактует как const C_A* и выдает ошибку, если с помощью них производится попытка модификации;
__> 2.2) если встретилась функция, то помещает в стек и переходит к 2);
__> 2.3) делает pop для стека.
__>3) анализ завершен

__>(тут еще оговорки, конечно, для рекурсивных вызовов, но это тоже решаемо на этапе анализа — просто не надо добавлять в стек то, что уже раньше встречалось)


Запретить модификацию всех экземпляров можно в runtime — сделать в классе дополнительное статическое поле со счетчиком const обращений и кидать исключение, если при вызове не-const метода этот счетчик не 0.
А на этапе компиляции это сделать не получится, так как у компилятора может не быть реализации класса C_B (или это вообще голый интерфейс), и, соответственно, он не сможет определить наличие обращение к не-const экземплярам C_A в нем.
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Re[12]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 23.09.15 13:00
Оценка:
Здравствуйте, VTT, Вы писали:

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


__>>нет. и вы тоже не поняли значит. речь не о том, чтобы не модифицировать ЗАДАННЫЙ ЭКЗЕМПЛЯР, а о том, чтобы запретить модификацию ВСЕ ЭКЗЕМПЛЯРЫ, если код их модификации попадает "в нитку", которая запускается вызовом class_const-метода.


__>>иными словами компилятор должен действовать так:


__>>0) заводит стек функций

__>>1) помещает в стек class_const-метод
__>>2) пока стек не пуст, берет верхний элемент стека и для него анализирует тело функции:
__>> 2.1) все указатели типа C_A* трактует как const C_A* и выдает ошибку, если с помощью них производится попытка модификации;
__>> 2.2) если встретилась функция, то помещает в стек и переходит к 2);
__>> 2.3) делает pop для стека.
__>>3) анализ завершен

__>>(тут еще оговорки, конечно, для рекурсивных вызовов, но это тоже решаемо на этапе анализа — просто не надо добавлять в стек то, что уже раньше встречалось)


VTT>Запретить модификацию всех экземпляров можно в runtime — сделать в классе дополнительное статическое поле со счетчиком const обращений и кидать исключение, если при вызове не-const метода этот счетчик не 0.


неее, в рантайме это не дело.

VTT>А на этапе компиляции это сделать не получится, так как у компилятора может не быть реализации класса C_B (или это вообще голый интерфейс), и, соответственно, он не сможет определить наличие обращение к не-const экземплярам C_A в нем.


не совсем понял, в каком месте (и в какой ситуации) не пройдет описанный мною выше алгоритм?
Re: "class const - метод" - можно ли организовать?
От: B0FEE664  
Дата: 23.09.15 13:18
Оценка:
Здравствуйте, _hum_, Вы писали:

__>Потому встал вопрос, есть ли в других языках или в новом стандарте с++ что-нибудь наподобие "class const — метода", который делает

__>константными ЛЮБЫЕ this данного класса в своей области видимости, и тем самым предотвращает всякое изменение любого (а значит и заданного)объекта данного класса?

Может и есть, но в С++ это не возможно, так как можно взять указатель на память, где лежит данное, привести его void*, сериализовать в строку, передать в другую функцию, десерилизовать, разыменовать и изменить данное. Отследить данную цепочку в момент компиляции не возможно.

__>Это понадобилось, в частности, для того, чтобы на этапе компиляции отлавливать зацикливания.

Ловите зацикливания в рантайме: флажок и RAII — всё, что для этого нужно.
И каждый день — без права на ошибку...
Re[2]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 23.09.15 13:26
Оценка:
Здравствуйте, B0FEE664, Вы писали:

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


__>>Потому встал вопрос, есть ли в других языках или в новом стандарте с++ что-нибудь наподобие "class const — метода", который делает

__>>константными ЛЮБЫЕ this данного класса в своей области видимости, и тем самым предотвращает всякое изменение любого (а значит и заданного)объекта данного класса?

BFE>Может и есть, но в С++ это не возможно, так как можно взять указатель на память, где лежит данное, привести его void*, сериализовать в строку, передать в другую функцию, десерилизовать, разыменовать и изменить данное. Отследить данную цепочку в момент компиляции не возможно.


ну, с таким подходом, так и const-спецификаторы невозможны, и в вобще ничего невозможно, кроме двочиных числе в ячеках памяти. речь же о том, чтобы дать возможность отслеживать НЕПРЕДНАМЕРЕННУЮ модификацию.

__>>Это понадобилось, в частности, для того, чтобы на этапе компиляции отлавливать зацикливания.

BFE>Ловите зацикливания в рантайме: флажок и RAII — всё, что для этого нужно.

ага, особенно, если это система автопилота самолетом.
Re[3]: "class const - метод" - можно ли организовать?
От: B0FEE664  
Дата: 23.09.15 13:37
Оценка:
Здравствуйте, _hum_, Вы писали:

__>ага, особенно, если это система автопилота самолетом.


В системе автопилота самолета используется паттерн сигнал-слот? Не делайте так.
И каждый день — без права на ошибку...
Re[4]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 23.09.15 14:22
Оценка:
Здравствуйте, B0FEE664, Вы писали:

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


__>>ага, особенно, если это система автопилота самолетом.


BFE>В системе автопилота самолета используется паттерн сигнал-слот? Не делайте так.


во-первых, вы так сказали, не я;
во-вторых, чем вас не устраивает сигнал-слот архитектура?
ну, а в-третьих, речь шла про общую проблему гарантии немодифицируемости методом полей объекта (решение которой, в частности, позволило бы решить проблему отслеживания циклов на этапе написания кода).
Re[5]: "class const - метод" - можно ли организовать?
От: c-smile Канада http://terrainformatica.com
Дата: 23.09.15 15:39
Оценка:
Здравствуйте, _hum_, Вы писали:

__>во-вторых, чем вас не устраивает сигнал-слот архитектура?


Не устраивает двумя моментами:

1. Возможность возникновения event/signal loop. Невозможность доказать статически отсутсвие таких циклов.
2. Инфраструктура signal/slot занимает ресурсы. Как минимум память.

При условии наличия альтернативных механизмов свободных от 1 и 2 использование сигнал-слот представляется спорным.
Re[6]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 23.09.15 15:49
Оценка:
Здравствуйте, c-smile, Вы писали:

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


__>>во-вторых, чем вас не устраивает сигнал-слот архитектура?


CS>Не устраивает двумя моментами:


CS>1. Возможность возникновения event/signal loop. Невозможность доказать статически отсутсвие таких циклов.


так а разве этим не грешат любые варианты организации двунаправленной связи между объектами?

CS>2. Инфраструктура signal/slot занимает ресурсы. Как минимум память.


CS>При условии наличия альтернативных механизмов свободных от 1 и 2 использование сигнал-слот представляется спорным.


а можно узнать об альтернативных механизмах, которые бы преодолевали эти два пункта, при том же самом функционале?
Re[5]: "class const - метод" - можно ли организовать?
От: B0FEE664  
Дата: 23.09.15 16:59
Оценка:
Здравствуйте, _hum_, Вы писали:

__>>>ага, особенно, если это система автопилота самолетом.

BFE>>В системе автопилота самолета используется паттерн сигнал-слот? Не делайте так.
__>во-первых, вы так сказали, не я;
Я не предлагал использовать паттерн сигнал-слот для машин от которых может зависеть жизнь людей.
А что, собственно, я сказал? Я предложил добавить проверку времени исполнения. Проверка времени исполнения не может существенно замедлить код использующий сигнал-слот-архитектуру, так как на данный момент любая реализация этого патерна включает в себя приведение типа при каждом вызове слот-функции. А всякое такое приведение типа включает в себя проверку указателя на NULL во время приведения типа. Так что добавление проверки одного флажка не может существенно замедлить работу.

__>во-вторых, чем вас не устраивает сигнал-слот архитектура?

Тем, что сигнал-слот архитектура существенно повышает сложность понимания кода при одновременном снижении сложности разработки. Создаётся иллюзия, что эта архитектура упрощает код при фактическом его усложнении из-за динамического связывания вызовов функций. (Собственно то, что вам потребовалось такая хитрая проверка константности говорит именно об этом.) Упрощенно можно сказать, что эта архитектура приводит к тому, что вместо кода:
void f()
{
   fun1();
   fun2();
   fun3();
   fun4();
}

программист видит код:
void f()
{
   ...
}

где троеточие заменяется вызовами функций в самых произвольных местах проекта. Таким образом теряется локальность изменений и за изменениями становится сложно следить.
Если вы действительно хотите применить эту архитектуру для чего-то такого, от чего может зависеть жизнь людей, то вам жизненно необходимо вести документацию отображающую все деревья вызовов сигнал-слот.

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

Это ведь не единственная проблема данной архитектуры. Замените
    void C_B::foo_B(void){ m_pA->set_x(10);}

на
    void C_B::foo_B(void){ delete m_pA;}

и вы получите не менее эпический краш даже при гарантии немодифицируемости методом полей объекта.
И каждый день — без права на ошибку...
Re[13]: "class const - метод" - можно ли организовать?
От: VTT http://vtt.to
Дата: 23.09.15 17:12
Оценка:
Здравствуйте, _hum_, Вы писали:

0) заводит стек функций

__>не совсем понял, в каком месте (и в какой ситуации) не пройдет описанный мною выше алгоритм?


Да с самого начала. В общем случае у компилятора нет никакой возможности построить этот стек вызовов. Вот например: метод foo_B класса C_B вызывается через указатель на абстрактный базовый класс. О том, что вызвался метод именно в классе C_B мы можем узнать только в runtime.
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Re[6]: "class const - метод" - можно ли организовать?
От: BulatZiganshin  
Дата: 23.09.15 18:15
Оценка:
Здравствуйте, B0FEE664, Вы писали:

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


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

а по сути дела такой подход позволяет внедрить что-то типа микросервисной архитектуры внутри одного приложения, когда одни модули предоставляю.т сервисы, другие их используют, и обе стороны работают соврешенно независимо, не пытаясь контролировать кто их вызывал или кого они вызвали "на другой стороне" шины
Люди, я люблю вас! Будьте бдительны!!!
Re[6]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 23.09.15 19:30
Оценка:
Здравствуйте, B0FEE664, Вы писали:


BFE>А что, собственно, я сказал? Я предложил добавить проверку времени исполнения. Проверка времени исполнения не может существенно замедлить код использующий сигнал-слот-архитектуру, так как на данный момент любая реализация этого патерна включает в себя приведение типа при каждом вызове слот-функции. А всякое такое приведение типа включает в себя проверку указателя на NULL во время приведения типа. Так что добавление проверки одного флажка не может существенно замедлить работу.


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

__>>во-вторых, чем вас не устраивает сигнал-слот архитектура?

BFE>Тем, что сигнал-слот архитектура существенно повышает сложность понимания кода при одновременном снижении сложности разработки. Создаётся иллюзия, что эта архитектура упрощает код при фактическом его усложнении из-за динамического связывания вызовов функций. (Собственно то, что вам потребовалось такая хитрая проверка константности говорит именно об этом.) Упрощенно можно сказать, что эта архитектура приводит к тому, что вместо кода:
BFE>
BFE>void f()
BFE>{
BFE>   fun1();
BFE>   fun2();
BFE>   fun3();
BFE>   fun4();
BFE>}
BFE>

BFE>программист видит код:
BFE>
BFE>void f()
BFE>{
BFE>   ...
BFE>}
BFE>

BFE>где троеточие заменяется вызовами функций в самых произвольных местах проекта. Таким образом теряется локальность изменений и за изменениями становится сложно следить.
BFE>Если вы действительно хотите применить эту архитектуру для чего-то такого, от чего может зависеть жизнь людей, то вам жизненно необходимо вести документацию отображающую все деревья вызовов сигнал-слот.

погодите-погодите, кто говорил, что речь идет о динамическом связывании? во многих случаях (в том числе в моем) можно обойтись и статическим (никаких виртуальных функций, никаких observer-pattern, — обычная "магия шаблонов". см., например, библиотеку boost). но от этого проблема не пропадает (что указывает на ее общий характер).

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

BFE>Это ведь не единственная проблема данной архитектуры. Замените
BFE>
BFE>    void C_B::foo_B(void){ m_pA->set_x(10);}
BFE>

BFE>на
BFE>
BFE>    void C_B::foo_B(void){ delete m_pA;}
BFE>

BFE>и вы получите не менее эпический краш даже при гарантии немодифицируемости методом полей объекта.

принципиальное отличие — вы можете и сами это проконтролировать (например, проверкой выполнения условия возможности удаления или использовать RAII). а вот отследить скрытые циклические зависимости, как в моем примере — это уже во многом неподъемная для программиста задача. потому и должен в этом случае приходить на помощь компилятор.
Re[14]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 23.09.15 19:56
Оценка:
Здравствуйте, VTT, Вы писали:

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


VTT>0) заводит стек функций


__>>не совсем понял, в каком месте (и в какой ситуации) не пройдет описанный мною выше алгоритм?


VTT>Да с самого начала. В общем случае у компилятора нет никакой возможности построить этот стек вызовов. Вот например: метод foo_B класса C_B вызывается через указатель на абстрактный базовый класс. О том, что вызвался метод именно в классе C_B мы можем узнать только в runtime.


кхм.. извиняюсь, а как, по-вашему, компилятор генерирует код, если он не в курсе, кто что будет вызывать?
может, давайте все-таки на конкретном примере, и я вместо компилятора попробую вам пройтись по алгоритму?
если брать мой первоначальный пример, и считать, что там
void foo_A(void)class_const;

то компилятор будет действовать так:
— первый раз пробегает по тексту программы и заносит себе в память информацию о том, какие функции в программе объявлены (какие у них сигнатуры), и где у каждой объявленной функции определение (текст тела функции);
— второй раз пробегает по тексту программы и, встретив декларацию функции "foo_A(void)class_const", заносит ее первой в стек;
а дальше по п. 2)
берет с вершины стека foo_A(void)class_const и переходит к ее телу (информация о том, где оно , уже имеется после первого прохода):
void C_A::foo_A(void)const
{
    m_pB->foo_B();
}

в теле видит вызов функции void foo_B(void), потому заносит его сигнатуру в стек; и т.д.

в каком месте он может споткнуться?

upd. может, вы имели в виду виртуальные функции? ну, так о них пока речь не шла (там можно либо все проверять, либо договориться, что в таких случаях виртуальные использовать нельзя).
Отредактировано 23.09.2015 20:02 _hum_ . Предыдущая версия .
Re[15]: "class const - метод" - можно ли организовать?
От: VTT http://vtt.to
Дата: 23.09.15 20:38
Оценка:
Здравствуйте, _hum_, Вы писали:

__>кхм.. извиняюсь, а как, по-вашему, компилятор генерирует код, если он не в курсе, кто что будет вызывать?


Для компиляции ему вполне достаточно знать сигнатуру метода и откуда он берется (содержится в этом же исполняемом файле или импортируется).

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


Дело в том, что как раз определения функции (текст тела функции) во время компиляции у компилятора может и не быть (я бы даже сказал что обычно нет).
Вот представьте, что класс C_B делает кто-то другой, а вам дает только заголовочный файл с объявлением этого класса и .dll (.lib) с его реализацией. А кода тела функции нет. И так со всеми системными и библиотечными функциями.
Даже если у вас есть код функции, он будет виден компилятору только если она inline или проект собирается с LTCG.

__>upd. может, вы имели в виду виртуальные функции? ну, так о них пока речь не шла (там можно либо все проверять, либо договориться, что в таких случаях виртуальные использовать нельзя).


Виртуальные я тоже имел ввиду. В начале вы вроде как упоминали сигнал-слоты, и на ум сразу приходит qt с его qobject и повальной виртуальностью.
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Re[16]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 23.09.15 21:17
Оценка:
Здравствуйте, VTT, Вы писали:

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


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


VTT>Дело в том, что как раз определения функции (текст тела функции) во время компиляции у компилятора может и не быть (я бы даже сказал что обычно нет).

VTT>Вот представьте, что класс C_B делает кто-то другой, а вам дает только заголовочный файл с объявлением этого класса и .dll (.lib) с его реализацией. А кода тела функции нет. И так со всеми системными и библиотечными функциями.
VTT>Даже если у вас есть код функции, он будет виден компилятору только если она inline или проект собирается с LTCG.

ну, разве только если с dll, потому как при статической компоновке (.lib) теоретически есть возможность перед построение окончательного кода, просмотреть библиотеки (почему-то интуитивно кажется, что выполнить алгоритм можно и по ассемблерному коду, зная изначально, какие типы участвуют в сигнатуре. а если и нет, то на будущее можно просто добавлять в них необходимую информацию).
но вообще, контраргумент понял — данное понятие на текущий момент не допускает раздельной компиляции...

__>>upd. может, вы имели в виду виртуальные функции? ну, так о них пока речь не шла (там можно либо все проверять, либо договориться, что в таких случаях виртуальные использовать нельзя).


VTT>Виртуальные я тоже имел ввиду. В начале вы вроде как упоминали сигнал-слоты, и на ум сразу приходит qt с его qobject и повальной виртуальностью.


не, я не люблю виртуальность, потому пока стараюсь обходиться статическим вариантом реализации сигналов-слотов (boost::signals2, да и qt ввел уже возможность статической реализации).
Re: "class const - метод" - можно ли организовать?
От: Кодт Россия  
Дата: 24.09.15 10:18
Оценка:
Здравствуйте, _hum_, Вы писали:

__>Потому встал вопрос, есть ли в других языках или в новом стандарте с++ что-нибудь наподобие "class const — метода", который делает константными ЛЮБЫЕ this данного класса в своей области видимости, и тем самым предотвращает всякое изменение любого (а значит и заданного)объекта данного класса?


Навесить константность на все объекты теоретически можно тремя способами:

1) через покрытие кода (мечты, мечты...)
class X;

void foo(X* x) {
  bar(x);
  #pragma TURN CONST ON
  buz(x); // вот здесь - и далее вглубь - константность навешана на всё
  #pragma TURN CONST OFF
  bar(x);
  buz(x);
}

компилятор должен провалиться в bar() и неявно навесить там константность

2) через типы — например, на шаблонах (фактически, это то же покрытие кода) — гору кода переписать, либо выбрать другой язык (скалу)
struct Mutable { Immutable& turn_const_on() const; };
struct Immutable : Mutable {};

template<class Traits>
void foo(Traits& t, X* x) {
  bar(t, x);
  buz(t.turn_const_on(), x);
  buz(t, x); // константность включится по требованию
}

void bar(Mutable& t, X* x);
void buz(Immutable& t, X const* x);


3) через, внезапно, рантаймовые проверки.
Просто натыкать флажков и ассертов
class X {
#ifdef _DEBUG
  bool is_mutable = true;
  thread_local static bool all_mutable = true;

  void turn_mutable(bool m) { is_mutable = m; }
  static void turn_all_mutable(bool m) { all_mutable = m; }
  void assert_mutable() { assert(is_mutable && all_mutable); }
#else
  void turn_mutable(bool m) {}
  static void turn_all_mutable(bool m) {}
  void assert_mutable() {}
#endif
  .....
};

void foo(X* x) {
  bar(x);
  X::turn_all_mutable(false);
  buz(x);
  X::turn_all_mutable(true);
  bar(x);
  buz(x);
}


Я нарочно не вдаюсь в нюансы — понятно, что тут логика скорее не двоичная, а счётчика вложенных запретов. И под это дело можно и RAII присобачить, и делать это нужно будет грамотно...
Перекуём баги на фичи!
Re: "class const - метод" - можно ли организовать?
От: SaZ  
Дата: 24.09.15 10:45
Оценка:
Соседняя ветка про Qt с топик стартером позволит более просто сформулировать хотелку автора.

_hum_ хочет переложить написание логики приложения с разработчика на компилятор. Кто знаком с Qt, может почитать изначальный вопрос: http://rsdn.ru/forum/cpp.qt/6188183.flat#6188183
Автор: _hum_
Дата: 20.09.15
Re[7]: "class const - метод" - можно ли организовать?
От: B0FEE664  
Дата: 24.09.15 13:13
Оценка:
Здравствуйте, _hum_, Вы писали:

__>самый главный недостаток динамического проверки, что ошибки ловятся уже в процессе работы, а значит, прерывают нормальное течение программы. к тому же не все их можно самому предугадать и словить. вот потому-то и стараются как можно больше проверок возложить на компилятор.


Тут я согласен.

__>погодите-погодите, кто говорил, что речь идет о динамическом связывании? во многих случаях (в том числе в моем) можно обойтись и статическим (никаких виртуальных функций, никаких observer-pattern, — обычная "магия шаблонов". см., например, библиотеку boost). но от этого проблема не пропадает (что указывает на ее общий характер).


Да, речь идёт о динамическом связывании, так как вы говорите об архитектуре сигнал-слот. Архитектура сигнал-слот сводится к динамическому созданию списков функций — других реализаций я не видел. (Я, кстати, и не уверен, что в принципе можно создать статический вариант этой архитектуры без использования шаблонных виртуальных методов, которых в С++ нет)

__>принципиальное отличие — вы можете и сами это проконтролировать (например, проверкой выполнения условия возможности удаления или использовать RAII). а вот отследить скрытые циклические зависимости, как в моем примере — это уже во многом неподъемная для программиста задача. потому и должен в этом случае приходить на помощь компилятор.


Я не вижу разницы. Нет никакой проблемы в том, чтобы узнать во время выполнения, что данная функция вызвана из самой себя через последовательность других функций.
И каждый день — без права на ошибку...
Re[8]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 24.09.15 15:24
Оценка:
Здравствуйте, B0FEE664, Вы писали:

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


__>>погодите-погодите, кто говорил, что речь идет о динамическом связывании? во многих случаях (в том числе в моем) можно обойтись и статическим (никаких виртуальных функций, никаких observer-pattern, — обычная "магия шаблонов". см., например, библиотеку boost). но от этого проблема не пропадает (что указывает на ее общий характер).


BFE>Да, речь идёт о динамическом связывании, так как вы говорите об архитектуре сигнал-слот. Архитектура сигнал-слот сводится к динамическому созданию списков функций — других реализаций я не видел. (Я, кстати, и не уверен, что в принципе можно создать статический вариант этой архитектуры без использования шаблонных виртуальных методов, которых в С++ нет)


возможно, дело в терминологии. я говорю лишь, что есть реализации сигнал-слот без использования виртуальных функций (просто используются более продвинутые варианты call back-функций, позволяющие на этапе компиляции отслеживать корректность (по типам) вызовов и писать код безо всяких понижающих приведений типов).

__>>принципиальное отличие — вы можете и сами это проконтролировать (например, проверкой выполнения условия возможности удаления или использовать RAII). а вот отследить скрытые циклические зависимости, как в моем примере — это уже во многом неподъемная для программиста задача. потому и должен в этом случае приходить на помощь компилятор.


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


вот здесь хотелось бы поподробнее (у вас 1000 разных функций, которые друг друга вызывают, и нужно определить, есть ли вариант зацикливания).
Re[8]: "class const - метод" - можно ли организовать?
От: Ops Россия  
Дата: 24.09.15 15:39
Оценка:
Здравствуйте, B0FEE664, Вы писали:

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


deleter у shared_ptr — это оно?
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re[2]: "class const - метод" - можно ли организовать?
От: _hum_ Беларусь  
Дата: 24.09.15 15:45
Оценка:
Здравствуйте, Кодт, Вы писали:

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


__>>Потому встал вопрос, есть ли в других языках или в новом стандарте с++ что-нибудь наподобие "class const — метода", который делает константными ЛЮБЫЕ this данного класса в своей области видимости, и тем самым предотвращает всякое изменение любого (а значит и заданного)объекта данного класса?


К>Навесить константность на все объекты теоретически можно тремя способами:


К>1) через покрытие кода (мечты, мечты...)

К>
К>class X;

К>void foo(X* x) {
К>  bar(x);
К>  #pragma TURN CONST ON
К>  buz(x); // вот здесь - и далее вглубь - константность навешана на всё
К>  #pragma TURN CONST OFF
К>  bar(x);
К>  buz(x);
К>}
К>

К>компилятор должен провалиться в bar() и неявно навесить там константность



К>2) через типы — например, на шаблонах (фактически, это то же покрытие кода) — гору кода переписать, либо выбрать другой язык (скалу)

К>
К>struct Mutable { Immutable& turn_const_on() const; };
К>struct Immutable : Mutable {};

К>template<class Traits>
К>void foo(Traits& t, X* x) {
К>  bar(t, x);
К>  buz(t.turn_const_on(), x);
К>  buz(t, x); // константность включится по требованию
К>}

К>void bar(Mutable& t, X* x);
К>void buz(Immutable& t, X const* x);
К>




К>3) через, внезапно, рантаймовые проверки.

К>Просто натыкать флажков и ассертов
К>
К>class X {
К>#ifdef _DEBUG
К>  bool is_mutable = true;
К>  thread_local static bool all_mutable = true;

К>  void turn_mutable(bool m) { is_mutable = m; }
К>  static void turn_all_mutable(bool m) { all_mutable = m; }
К>  void assert_mutable() { assert(is_mutable && all_mutable); }
К>#else
К>  void turn_mutable(bool m) {}
К>  static void turn_all_mutable(bool m) {}
К>  void assert_mutable() {}
К>#endif
К>  .....
К>};

К>void foo(X* x) {
К>  bar(x);
К>  X::turn_all_mutable(false);
К>  buz(x);
К>  X::turn_all_mutable(true);
К>  bar(x);
К>  buz(x);
К>}
К>


К>Я нарочно не вдаюсь в нюансы — понятно, что тут логика скорее не двоичная, а счётчика вложенных запретов. И под это дело можно и RAII присобачить, и делать это нужно будет грамотно...


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