Здравствуйте, AVC, Вы писали:
AVC>>>Я так и не понял, в чем именно ошибка. К>>Ошибка К>>- локально, в неправильном использовании прав доступа К>>- если смотреть шире, в слишком мягкой политике языка
AVC>Я и сейчас не вижу ошибки.
Ошибка логическая, компилятором не просекаемая.
Она стоит в одном ряду с
const double PI = exp(1.0);
Точнее, как раз её-то просечь можно.
AVC>Так как Вы говорите о неправильном использовании прав доступа, то где-то должно существовать правильное использование. AVC>Предлагаю сделать так. Вы пишете правильный вариант. (Можно на Си++. Я прощу. ) AVC>А я таким путем проникну в суть вещей.
Ну я уже писал выше — dyn_object<T>, pointer<T>
AVC>>>Я вообще не вижу ошибки. (Код, конечно, странный. Но ведь неизвестно, для чего он.) AVC>>>Вообще, человек и компилятор отвечают каждый за свой участок. AVC>>>Человек за осмысленность и смысловую корректность вычислений. AVC>>>Компилятор — за безопасность системы типов. К>>То есть, ты считаешь, что право С++ удалять указатель — это криминал, а право Оберона ковырять объект, доступный по неконстантной ссылке или по указателю — это программист сам дурак. А почему не наоборот?
AVC>Я что-то не понимаю. AVC>Вы сами написали utilize(VAR p: Data). Если бы не хотели позволить модификацию p, написали бы utilize(p: Data), и дело с концом.
Не с концом. Давай введём ещё один уровень опосредования
TYPE Foo = POINTER TO RECORD x:Integer; END;
Bar = POINTER TO RECORD f:Foo; END;
PROCEDURE deface(b:Bar); (* казалось бы, константа... *)BEGIN
b.f := NEW Foo; (* но объект поменять - как нефиг делать *)
b.f.x := 456;
END;
PROCEDURE main();
VAR a,b:Foo;
c:Bar;
BEGIN
a := NEW Foo;
a.x := 123;
c := NEW Bar;
c.f := a;
deface(c);
b := c.f;
if(a.x <> b.x) Write("приплыли");
END;
AVC>>>Вам не удалось (по крайней мере, в данном случае) обмануть компилятор Оберона. AVC>>>Так что ничего общего с "глюкавостью" Си++ здесь нет.
К>>А вот здесь я как апологет С++ скажу, что Оберон отдыхает в сторонке! К>>С помощью шаблонов можно очень тонко регулировать права использования разделяемых данных (включая параметры, передаваемые в и из функции).
AVC>Например, в компонентном Паскале кроме VAR есть спецификаторы IN и OUT. AVC>И не нужно быть гуру обобщенного программирования. AVC>При принятии Oakwood guidelines обсуждался вопрос о параметрах только для чтения (VAR p-: Data), но был отклонен (на вполне разумных основаниях).
Кстати, с константностью есть ещё один момент — а именно, глубина распространения константности.
Объект, доступный по константному указателю (например, члену константного объекта) — константный или нет?
С++ считает, что нет, хотя в ряде случаев это может явиться источником ошибок. А в другом ряде случаев — это не ошибка.
Lint такие вещи старается находить и предупреждать.
Что здесь можно сделать? Ввести два типа указателей, с распространением константности и без распространения.
Опять же, средствами С++,
Кто-то может сказать — ну и изврат же это! Вместо T* писать constable_pointer<T>, dyn_object<T> и т.п.
Но ведь это не сильно длиннее Паскаля, ПЛ, Оберона — POINTER TO T.
Я сейчас фонтанирую идеями насчёт системы шаблонов. Пока что были озвучены
— права на delete/delete[],
— права на адресную арифметику (от которой, впрочем, можно и совсем отказаться),
— транзитивность константности (и, кстати, volatile...)
Ещё вспомним про разнообразные политики владения (монопольное, разделяемое, эстафетное как у auto_ptr)...
Нашёлся бы кто-то, кто приведёт все эти фичи в систему (а может быть, даже и я — как раз сейчас новый проект стартует, там постараемся сделать по-человечески).
К>PROCEDURE utilize(VAR p: Data); (* здесь — заявлены неправильные полномочия *) К>BEGIN К> Write(p); К> touch(p); (* а с виду и не поймёшь, что переменную изменили... *) К> p.x := 3; К>END;
К>PROCEDURE main(); К>VAR i,j : POINTER TO Integer; К>BEGIN К> i := NEW Data; i.x := 7; К> j := i; (* два указателя на один объект *) К> utilize(j); К> if(i.x <> j.x) Write('приплыли'); К>END; К>[/pascal]
В Net эта проблема решается через явное указание ref или out в вызываемых методах.
PROCEDURE utilize(VAR p: Data); (* здесь — заявлены неправильные полномочия *)
BEGIN
Write(p);
touch(var p); (* а с виду и не поймёшь, что переменную изменили... *)
p.x := 3;
END;
PROCEDURE main();
VAR i,j : POINTER TO Integer;
BEGIN
i := NEW Data; i.x := 7;
j := i; (* два указателя на один объект *)
utilize(var j);
if(i.x <> j.x) Write('приплыли');
END; К>[/pascal]
Многие в Net положительно отнеслись к такому синтаксису (как и я). Особенно когда не знаешь всех методов и такого рода ошибки уменьшаются и читабельность увеличивается.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
и солнце б утром не вставало, когда бы не было меня
На самом деле, использование расширения необязательно.
Вот немного модифицированный предыдущий пример.
<*+MAIN*>
MODULE O2Ext;
IMPORT Out;
TYPE
IPtr = POINTER TO RECORD x: INTEGER END;
PPtr = POINTER TO PRec;
PRec = RECORD p: IPtr END;
VAR
p: IPtr;
q: PPtr;
PROCEDURE test(q: PRec);
VAR p: IPtr;
BEGIN
NEW(p); p.x := 2;
q.p := p;
END test;
BEGIN
NEW(p); p.x := 1;
NEW(q); q.p := p;
test(q^);
IF q.p.x # p.x THEN
Out.String("Oops!");
ELSE
Out.String("Oberon forever!");
END;
END O2Ext.
Теперь он проходит компиляцию, но печатает, конечно, Oberon forever!
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Здравствуйте, Кодт, Вы писали:
AVC>>Я что-то не понимаю. AVC>>Вы сами написали utilize(VAR p: Data). Если бы не хотели позволить модификацию p, написали бы utilize(p: Data), и дело с концом. К>Не с концом. Давай введём ещё один уровень опосредования К>
К>TYPE Foo = POINTER TO RECORD x:Integer; END;
К> Bar = POINTER TO RECORD f:Foo; END;
К>PROCEDURE deface(b:Bar); (* казалось бы, константа... *)
К>BEGIN
К> b.f := NEW Foo; (* но объект поменять - как нефиг делать *)
К> b.f.x := 456;
К>END;
К>PROCEDURE main();
К>VAR a,b:Foo;
К> c:Bar;
К>BEGIN
К> a := NEW Foo;
К> a.x := 123;
К> c := NEW Bar;
К> c.f := a;
К> deface(c);
К> b := c.f;
К> if(a.x <> b.x) Write("приплыли");
К>END;
К>
Так. Начинаю видеть проблему.
Вот почему мне нужна (разумная) критика.
Отвечаю пока кратко.
Проблему признаю. Но, кажется, в Обероне она решается просто.
Беру компилятор XDS. (Наверное, в руки? )
Он позволяет применять (по требованию) спецификатор - (read-only) для параметров-значений.
Вот пример кода. (Прошу прощения за его "аляповатость".)
<*+MAIN*>
<*+O2EXTENSIONS*> (* разрешаю использовать (в частности) readonly параметры *)
MODULE O2Ext;
IMPORT Out;
TYPE
IPtr = POINTER TO RECORD x: INTEGER END;
PPtr = POINTER TO PRec;
PRec = RECORD p: IPtr END;
VAR
p: IPtr;
q: PPtr;
PROCEDURE test(q-: PRec);
VAR p: IPtr;
BEGIN
NEW(p); p.x := 2;
q.p := p; (* эту строку не пропускает компилятор *)END test;
BEGIN
NEW(p); p.x := 1;
NEW(q); q.p := p;
test(q^);
IF q.p.x # p.x THEN Out.String("Oops!"); END;
END O2Ext.
Компилятор не допускает изменения параметра для чтения.
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Здравствуйте, RailRoadMan, Вы писали:
RRM>Честно говоря, дальше с вам спорить не считаю нужным. Если вы помните, этот спор начался с того, что мне было интересно узнать про трудности с указателями. Я узнал, но не проникся, видимо мне они пока серьезных проблем не доставляли.
RRM>Если вам по какой-то причине нужен оберон, хорошо, что он есть, мне Оберон не нужен, может пока, может вообще.
RRM>P.S. Просто раздражает, когда Оберон (и иже с ними) выставляют в виде некой панацеи от всего. Но это не к вам.
Я здесь вступлюсь за AVC
Беда языка С++ в том, что очень много опасных преобразований он позволяет делать неявно.
Требуются неслабые усилия, чтобы пресечь эти попытки.
Самое простое: преобразование модели "указатель" в "динамический объект".
void utilize(int* x)
{
cout << *x << endl;
delete x;
}
int main()
{
utilize(new int(7));
int i = 3;
utilize(&i);
}
Как видите, где-то в этом коде произошло криминальное изменение семантики — но где именно, в точке delete x или в utilize(&i) ? Знают только авторы кода, да и те после вчерашней пьянки забыли.
Впрочем, средства С++ позволяют разрулить эту ситуацию.
Здесь уже стало видно, где именно происходит преобразование моделей.
Да, на Обероне нужно гораздо меньше выкручиваться на этот счёт.
Как в С++ весьма мощным средством раздачи по пальцам является накладывание константности, так в Обероне — разделение на статические и динамические объекты.
Впрочем, от кривых рук не спасёт:
TYPE Data = POINTER TO RECORD x: Integer; END;
PROCETUDE touch(VAR p: Data);
BEGIN
p := NEW Data;
END;
PROCEDURE utilize(VAR p: Data); (* здесь - заявлены неправильные полномочия *)BEGIN
Write(p);
touch(p); (* а с виду и не поймёшь, что переменную изменили... *)
p.x := 3;
END;
PROCEDURE main();
VAR i,j : POINTER TO Integer;
BEGIN
i := NEW Data; i.x := 7;
j := i; (* два указателя на один объект *)
utilize(j);
if(i.x <> j.x) Write('приплыли');
END;
Здравствуйте, Serginio1, Вы писали:
S> В Net эта проблема решается через явное указание ref или out в вызываемых методах. S> Многие в Net положительно отнеслись к такому синтаксису (как и я). Особенно когда не знаешь всех методов и такого рода ошибки уменьшаются и читабельность увеличивается.
Я такое делаю в С++ при передаче out и inout параметров в COM-овские методы.
Заодно решается вопрос о приведении типов.
Здравствуйте, AVC, Вы писали:
AVC>Но "критический запал" Кодта остается мне непонятным (в данном случае). AVC>Ведь в Обероне нет перегрузки методов, позволяющей применять VAR произвольно.
Я не на Оберон нападаю! Я почувствовал запах дичи касающейся программирования вообще.
И в С++, и в Обероне есть одинаковые проблемы, просто в С++ дырка пошире, зато и заплатки навесить попроще
Если уж на кого катить бочку, так это на старый добрый Фортран. Вот там — веселье с константностью!
Впрочем, у всех этих изысков есть оборотная сторона: количество legacy code.
Например, в моей компании — исходников порядка сотен мегабайт, если не гигабайт. Починить их все — нереально. Поэтому, если придётся скрещивать новый, красивый, безопасный код со старым — то возникнут разнообразные проблемы (конечно, решаемые, но вряд ли решаемые тривиально).
У Оберона с этим, наверное, проще. Во-первых, меньше кода написано, во-вторых, часть проблем была на корню пресечена.
Здравствуйте, Кодт, Вы писали:
К>Да, на Обероне нужно гораздо меньше выкручиваться на этот счёт. К>Как в С++ весьма мощным средством раздачи по пальцам является накладывание константности, так в Обероне — разделение на статические и динамические объекты. К>Впрочем, от кривых рук не спасёт: К>
К>TYPE Data = POINTER TO RECORD x: Integer; END;
К>PROCETUDE touch(VAR p: Data);
К>BEGIN
К> p := NEW Data;
К>END;
К>PROCEDURE utilize(VAR p: Data); (* здесь - заявлены неправильные полномочия *)
К>BEGIN
К> Write(p);
К> touch(p); (* а с виду и не поймёшь, что переменную изменили... *)
К> p.x := 3;
К>END;
К>PROCEDURE main();
К>VAR i,j : POINTER TO Integer;
К>BEGIN
К> i := NEW Data; i.x := 7;
К> j := i; (* два указателя на один объект *)
К> utilize(j);
К> if(i.x <> j.x) Write('приплыли');
К>END;
К>
А куда, собственно, приплыли?
Ошибки вроде не случилось.
Если бы процедура utilize не предполагала возможности изменения указателя, то там бы не стоял квалификатор VAR. А т.к. VAR стоит, то компилятор в курсе. Если потребуется, "сгенерит" необходимую проверку.
Есть более трудные ситуации (например, смена динамического типа указателя в теле type guard WITH), но и они в Обероне пристойно "разруливаются".
Цитирую Oakwood guidelines:
2.4 WITH and guarded variables
It is possible to alter a guarded pointer variable within the scope of a guarding WITH
statement, example:
TYPE
T = RECORD END; P = POINTER TO T;
T1 = RECORD (T) END; P1 = POINTER TO T1;
T2 = RECORD (T) END; P2 = POINTER TO T2;
PROCEDURE X;
VAR p: P; p1: P1; p2: P2;
PROCEDURE Y;
BEGIN
The Oakwood Guidelines for Oberon-2 Compiler DevelopersOctober 20, 1995 10
p := p2
END Y;
BEGIN
NEW (p); NEW(p1); NEW(p2); p := p1;
WITH p: P1 DO
Y (*p is now of type P2 and not P1*)
END
END X;
A practical way to handle this is :
If the compiler can be sure it is safe then give no warning message. If there can be any
doubt then do give a warning message. A sophisticated compiler could automatically
insert the additional relevant type guard checks.
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Здравствуйте, AVC, Вы писали:
AVC>А куда, собственно, приплыли? AVC>Ошибки вроде не случилось. AVC>Если бы процедура utilize не предполагала возможности изменения указателя, то там бы не стоял квалификатор VAR. А т.к. VAR стоит, то компилятор в курсе. Если потребуется, "сгенерит" необходимую проверку.
Компилятор-то в курсе, да у программиста руки были кривые и глаза косые.
Ведь можно сказать, что компилятор С/С++ тоже в курсе, и раз написали "указатель", то и надругаться над ним можем во всём спектре (в том числе — адресная арифметика и менеджмент памяти), а не только в том, которое было задумано.
Здравствуйте, Кодт, Вы писали:
AVC>>А куда, собственно, приплыли? AVC>>Ошибки вроде не случилось. AVC>>Если бы процедура utilize не предполагала возможности изменения указателя, то там бы не стоял квалификатор VAR. А т.к. VAR стоит, то компилятор в курсе. Если потребуется, "сгенерит" необходимую проверку. К>Компилятор-то в курсе, да у программиста руки были кривые и глаза косые. К>Ведь можно сказать, что компилятор С/С++ тоже в курсе, и раз написали "указатель", то и надругаться над ним можем во всём спектре (в том числе — адресная арифметика и менеджмент памяти), а не только в том, которое было задумано.
Я так и не понял, в чем именно ошибка.
Ваш код примерно соответствует следующему:
typedef struct { int x; } *Data;
void main()
{
Data *p, *q;
p = malloc(sizeof *p);
p->x = 7;
q = p; /* два указателя на один объект */
q = malloc(sizeof *q); /* уже нет */
q->x = 3;
if (p->x != q->x)
printf("приехали"); /* здесь Вы кричите "пожар!" А в чем собственно дело? */
}
Я вообще не вижу ошибки. (Код, конечно, странный. Но ведь неизвестно, для чего он.)
Вообще, человек и компилятор отвечают каждый за свой участок.
Человек за осмысленность и смысловую корректность вычислений.
Компилятор — за безопасность системы типов.
Вам не удалось (по крайней мере, в данном случае) обмануть компилятор Оберона.
Так что ничего общего с "глюкавостью" Си++ здесь нет.
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Просто сказалась привычка объявлять указатели явно (со звездочкой).
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Здравствуйте, AVC, Вы писали:
AVC>Я так и не понял, в чем именно ошибка.
Ошибка
— локально, в неправильном использовании прав доступа
— если смотреть шире, в слишком мягкой политике языка
AVC>Я вообще не вижу ошибки. (Код, конечно, странный. Но ведь неизвестно, для чего он.) AVC>Вообще, человек и компилятор отвечают каждый за свой участок. AVC>Человек за осмысленность и смысловую корректность вычислений. AVC>Компилятор — за безопасность системы типов.
То есть, ты считаешь, что право С++ удалять указатель — это криминал, а право Оберона ковырять объект, доступный по неконстантной ссылке или по указателю — это программист сам дурак. А почему не наоборот?
AVC>Вам не удалось (по крайней мере, в данном случае) обмануть компилятор Оберона. AVC>Так что ничего общего с "глюкавостью" Си++ здесь нет.
А вот здесь я как апологет С++ скажу, что Оберон отдыхает в сторонке!
С помощью шаблонов можно очень тонко регулировать права использования разделяемых данных (включая параметры, передаваемые в и из функции).
Правда, "строгость законов компенсируется необязательностью их исполнения", то есть требует от программистов соглашения по кодированию. Например, не использовать голые указатели.
Практический пример — ATL. Никто не мешает забить на CComPtr и пользоваться голым IXxxx*, мучительно вспоминая, сколько раз ты сделал AddRef... но очень быстро привыкаешь к хорошему
К>А вот здесь я как апологет С++ скажу, что Оберон отдыхает в сторонке! К>С помощью шаблонов можно очень тонко регулировать права использования разделяемых данных (включая параметры, передаваемые в и из функции).
Если смотреть на Net, то там полное торжество идей Вирта. Дженерики появятся и в Обероне.Net.
Интерес оберона в том, что уже есть операционка на нем. Лонгхорн выйдет еще не скоро , да и натива в нем будет немало.
Как уже говорил для существует Compact фреймворк итд. Для определенного круга задач не требуются глобальные ОСи.
А по конкретные задачи вполне может подойти и оберон системы. Все таки они живут и развиваются.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Кодт, Вы писали:
AVC>>Я так и не понял, в чем именно ошибка. К>Ошибка К>- локально, в неправильном использовании прав доступа К>- если смотреть шире, в слишком мягкой политике языка
Я и сейчас не вижу ошибки.
Так как Вы говорите о неправильном использовании прав доступа, то где-то должно существовать правильное использование.
Предлагаю сделать так. Вы пишете правильный вариант. (Можно на Си++. Я прощу. )
А я таким путем проникну в суть вещей.
AVC>>Я вообще не вижу ошибки. (Код, конечно, странный. Но ведь неизвестно, для чего он.) AVC>>Вообще, человек и компилятор отвечают каждый за свой участок. AVC>>Человек за осмысленность и смысловую корректность вычислений. AVC>>Компилятор — за безопасность системы типов. К>То есть, ты считаешь, что право С++ удалять указатель — это криминал, а право Оберона ковырять объект, доступный по неконстантной ссылке или по указателю — это программист сам дурак. А почему не наоборот?
Я что-то не понимаю.
Вы сами написали utilize(VAR p: Data). Если бы не хотели позволить модификацию p, написали бы utilize(p: Data), и дело с концом.
AVC>>Вам не удалось (по крайней мере, в данном случае) обмануть компилятор Оберона. AVC>>Так что ничего общего с "глюкавостью" Си++ здесь нет.
К>А вот здесь я как апологет С++ скажу, что Оберон отдыхает в сторонке! К>С помощью шаблонов можно очень тонко регулировать права использования разделяемых данных (включая параметры, передаваемые в и из функции).
Например, в компонентном Паскале кроме VAR есть спецификаторы IN и OUT.
И не нужно быть гуру обобщенного программирования.
При принятии Oakwood guidelines обсуждался вопрос о параметрах только для чтения (VAR p-: Data), но был отклонен (на вполне разумных основаниях).
К>Правда, "строгость законов компенсируется необязательностью их исполнения", то есть требует от программистов соглашения по кодированию. Например, не использовать голые указатели. К>Практический пример — ATL. Никто не мешает забить на CComPtr и пользоваться голым IXxxx*, мучительно вспоминая, сколько раз ты сделал AddRef... но очень быстро привыкаешь к хорошему
А вот это и есть суровая правда жизни.
На всякую конвенцию найдется свой Паниковский.
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
A AVC>Я что-то не понимаю. AVC>Вы сами написали utilize(VAR p: Data). Если бы не хотели позволить модификацию p, написали бы utilize(p: Data), и дело с концом.
В Net из за перегрузки методов может существовать
utilize(VAR p: Data)
и
utilize(p: Data)
Поэтому первый метод ты обязан вызвать как
utilize(VAR p)
Многие по этому поводу возмущались. Но мне лично вызов с явным указанием нравится больше, даже в языках не поддерживающие перегрузку методов. Все сразу видно не вникая в объявление метода
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S> В Net из за перегрузки методов может существовать S> utilize(VAR p: Data) S> и S> utilize(p: Data) S> Поэтому первый метод ты обязан вызвать как S> utilize(VAR p) S> Многие по этому поводу возмущались. Но мне лично вызов с явным указанием нравится больше, даже в языках не поддерживающие перегрузку методов. Все сразу видно не вникая в объявление метода
Спасибо.
Это мне пока понятнее, чем пример, приведенный Кодтом в качестве критики.
Думаю, что внесение ясности в код стоит того, чтобы написать лишний раз VAR.
Но "критический запал" Кодта остается мне непонятным (в данном случае).
Ведь в Обероне нет перегрузки методов, позволяющей применять VAR произвольно.
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Здравствуйте, AVC, Вы писали:
AVC>Но "критический запал" Кодта остается мне непонятным (в данном случае). AVC>Ведь в Обероне нет перегрузки методов, позволяющей применять VAR произвольно.
Наверное главное в этом
touch(p); (* а с виду и не поймёшь, что переменную изменили... *)
хотя можно былобы и так
touch({* var *} p); (не знаю какие комментарии в обероне)
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S> Наверное главное в этом S> touch(p); (* а с виду и не поймёшь, что переменную изменили... *) S> хотя можно былобы и так S> touch({* var *} p); (не знаю какие комментарии в обероне)
Комментарии в Обероне — круглые скобки со звездочками: (* комментарий *).
Комментарии могут быть вложенными.
Кодт только что прислал большой пост; может быть сейчас все прояснится.
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
AVC>Комментарии в Обероне — круглые скобки со звездочками: (* комментарий *).
Эх а ведь хотел круглые скобочки (просто в Delphi и те и те катят.
На самом деле по const например для Delphi существуют ограничения, да и const там для объектов поддерживающих подсчет ссылок
TProba = class
I:Integer;
Procedure ConstMethod(Const A:Tproba);
Procedure NotConstMethod(Const A:Tproba);
end;
procedure TForm1.Button1Click(Sender: TObject);
var A: Tproba;
begin
A:=TProba.Create;
A.ConstMethod(a);
end;
{ TProba }procedure TProba.ConstMethod(const A: Tproba);
begin
A:=TProba.Create; // не прокатывает
A.I:=3; // прокатывает
NotConstMethod(A); // прокатывает end;
procedure TProba.NotConstMethod(const A: Tproba);
begin
A.I:=3;
end;
А как с этим в обероне. Кстати в Net отказались от Const наверное по причине отсутствия подсчета ссылок и трудности предотвращения изменений как вызоа NotConstMethod из ConstMethod
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S> А как с этим в обероне. Кстати в Net отказались от Const наверное по причине отсутствия подсчета ссылок и трудности предотвращения изменений как вызоа NotConstMethod из ConstMethod
(следует читать с большой важностью ) Как коренной Си++янин не в курсе тонкостей каких-то там Delphi.
(Просто так получилось. На объектном Турбо-паскале писал в начале 90-х.)
Создается впечатление, что class в Delphi изначально ссылочный тип (я прав?), а модификатор const относится только к самому указателю.
В Обероне есть возможность передавать записи по значению. (Это не значит, что они обязательно копируются в стек. Просто гарантируется, что исходная запись не изменится.)
На самом деле, даже расширение "-" не обязательно.
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Здравствуйте, AVC, Вы писали:
AVC>Здравствуйте, Serginio1, Вы писали:
S>> А как с этим в обероне. Кстати в Net отказались от Const наверное по причине отсутствия подсчета ссылок и трудности предотвращения изменений как вызоа NotConstMethod из ConstMethod
AVC>(следует читать с большой важностью ) Как коренной Си++янин не в курсе тонкостей каких-то там Delphi. AVC>(Просто так получилось. На объектном Турбо-паскале писал в начале 90-х.)
Просто Delphi побочный продукт творений Вирта, многое пришло из пуре паскаля. AVC>Создается впечатление, что class в Delphi изначально ссылочный тип (я прав?), а модификатор const относится только к самому указателю.
Да это var только не изменяемый. Нужен в основном для строк, интерфейсов, динамических массивов что бы не городить обработчики исключений и подсчет ссылок, увеличивая тем самым скорость и огребая определенные проблемы. AVC>В Обероне есть возможность передавать записи по значению. (Это не значит, что они обязательно копируются в стек. Просто гарантируется, что исходная запись не изменится.) AVC>На самом деле, даже расширение "-" не обязательно.
Кстати разворачивает компилятор NotConstMethod из ConstMethod или вся проверка идет в теле метода????
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
AVC>>В Обероне есть возможность передавать записи по значению. (Это не значит, что они обязательно копируются в стек. Просто гарантируется, что исходная запись не изменится.) AVC>>На самом деле, даже расширение "-" не обязательно. S> Кстати разворачивает компилятор NotConstMethod из ConstMethod или вся проверка идет в теле метода????
За нехваткой времени (сегодня) отвечаю сразу и кратко.
С целью выяснить именно это еще не дизассемблировал код, порождаемый XDS.
Но предполагаю то же, что и Вы: вероятно, необходимость копирования выясняется в момент компиляции вызываемой процедуры.
Если это предположение не верно, впоследствии сообщу, как именно это реализовано.
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Здравствуйте, Кодт, Вы писали:
К>Кстати, с константностью есть ещё один момент — а именно, глубина распространения константности.
Добравшись домой, до меня дошла глубина Вашего "коварства". (почти по Чехову. )
Т.е. Ваша мысль состоит в том, что даже если мы предохранились от "порчи" некой рекурсивной структуры данных на n-м шаге, у нас возникает такая же проблема на (n+1)-м шаге?
И Вы предлагаете "лечить" эту проблему с помощью новой разновидности умных указателей?
Виноват, "въехал" не с первого раза.
Интересная мысль. Надо будет подумать.
К>Что здесь можно сделать? Ввести два типа указателей, с распространением константности и без распространения. К>Опять же, средствами С++,
Посмотрел код. Наверное, такое решение "прокатит".
Но вот что смущает. У Вас уже есть много разновидностей умных указателей.
А если потребуется совместить положительные качества разных умных указателей?
Вы предпочтете (а) написать новый класс умных указателей, (б) применить множественное наследование, (в) применить какую-нибудь "суперпозицию" шаблонов?
Шутка.
Я просто к тому, что кодирование на Си++ может превратиться в мучение.
Лично я поискал бы другое решение.
Например, спрятал бы указатели вообще, раз у нас пошла такая рекурсия.
Если реализация АТД требует рекурсивной структуры, то скрыл бы указатели вообще и управлял бы ими исключительно через операции самого АТД.
Например, как в узле бинарного дерева (если нужно дерево):
MODULE Trees;
TYPE
Node* = POINTER TO NodeDesc;
NodeDesс* = RECORD
left, right: Node; (* эти указатели существуют только для модуля Trees *)END;
Можно помещать в дерево самые разные производные от записи NodeDesc, но указатели left и right доступны только из модуля Trees. Следовательно, никто не сможет их "испортить".
Может, я не слишком складно выразил свою мысль (все-таки ночь уже на дворе. ).
Но смысл моего полуночного лепета в том, что должно найтись и другое решение, помимо умных указателей Си++.
К>Кто-то может сказать — ну и изврат же это! Вместо T* писать constable_pointer<T>, dyn_object<T> и т.п. К>Но ведь это не сильно длиннее Паскаля, ПЛ, Оберона — POINTER TO T.
Думаю, что это не изврат (по крайней мере в Си++).
Но надо, чтобы люди заранее знали: если уж начал программировать на Си++ — придется пускаться во все тяжкие.
(А то вот Cyberax обещает райскую жизнь: boost в лапы, и сразу весь оброс шелковистыми волосами... до самого хвоста.)
А дальше каждый волен поступать по-своему: Вы изобретаете новые идиомы, а я ищу лучший язык (так как идиом в Си++ и так много, а память у меня плохая).
К>Нашёлся бы кто-то, кто приведёт все эти фичи в систему (а может быть, даже и я — как раз сейчас новый проект стартует, там постараемся сделать по-человечески).
Желаю удачи! Главное — идеи у Вас есть.
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Здравствуйте, AVC, Вы писали:
AVC>Но вот что смущает. У Вас уже есть много разновидностей умных указателей. AVC>А если потребуется совместить положительные качества разных умных указателей? AVC>Вы предпочтете (а) написать новый класс умных указателей, (б) применить множественное наследование, (в) применить какую-нибудь "суперпозицию" шаблонов? AVC>Шутка.
Не знаю, не знаю... Может быть, всё можно разрулить через особо хитрые traits.
В конце концов, параметризовать умный указатель битовыми флагами, отвечающими той или иной характеристике.
AVC>Я просто к тому, что кодирование на Си++ может превратиться в мучение. AVC>Лично я поискал бы другое решение. AVC>Например, спрятал бы указатели вообще, раз у нас пошла такая рекурсия.
Да, нужно подумать, какие ещё бывают способы косвенного доступа. И что из этого может получиться...
К>>Кто-то может сказать — ну и изврат же это! Вместо T* писать constable_pointer<T>, dyn_object<T> и т.п. К>>Но ведь это не сильно длиннее Паскаля, ПЛ, Оберона — POINTER TO T.
AVC>Думаю, что это не изврат (по крайней мере в Си++). AVC>Но надо, чтобы люди заранее знали: если уж начал программировать на Си++ — придется пускаться во все тяжкие. AVC>(А то вот Cyberax обещает райскую жизнь: boost в лапы, и сразу весь оброс шелковистыми волосами... до самого хвоста.) AVC>А дальше каждый волен поступать по-своему: Вы изобретаете новые идиомы, а я ищу лучший язык (так как идиом в Си++ и так много, а память у меня плохая).
Идиомы — они как бы универсальны; только в некоторых языках они встроены, а в других приходится делать ручками.
Та же телега с константностью указателя... Проще всего спрятать член-данное и отдавать наружу через функции, уже адаптированный (с навешанной подходящей константностью).
struct Foo { int x; };
class Bar
{
Foo* f_;
Foo* g_;
mutable Foo* h_;
public:
// распространение константности на динамический объект (агрегат)
Foo*& f() { return f_; }
const Foo* const& f() const { return f_; }
// независимый объект
Foo*& g() { return g_; }
Foo* const& g() const { return g_; }
// кэш (изменение не влияет на логическую константность)
Foo*& h() const { return h_; }
};
void deface(Bar& b1, const Bar& b2)
{
b1.f()->x = 1;
b1.f() = new Foo;
b2.f()->x = 1; // error
b2.f() = new Foo; // error
b2.g()->x = 1; // ok
b2.g() = new Foo; // error
b2.h() = new Foo; // ok
}
Опять же, я пишу примеры для С++, потому что он мне практически ближе. В Обероне могут по-другому стоять акценты.
В конце концов, если используешь C++ и MFC или COM/ATL, то от константности в большом количестве мест приходится отказываться.
Здравствуйте, Serginio1, Вы писали:
S> А как с этим в обероне. Кстати в Net отказались от Const наверное по причине отсутствия подсчета ссылок и трудности предотвращения изменений как вызоа NotConstMethod из ConstMethod
Разработчики просто решили, что "это не так уж и нужно, а затраты на внедрение слишком велики".
Хотя я думаю, что это была ошибка с их стороны
У меня есть предложение: отделить ветку по теме усиления/деградации ограничений (константность, управление памятью и т.д.) при косвенном доступе (по указателю, по ссылке)
Здравствуйте, Кодт, Вы писали:
К>У меня есть предложение: отделить ветку по теме усиления/деградации ограничений (константность, управление памятью и т.д.) при косвенном доступе (по указателю, по ссылке)
Разумная мысль.
Мне кажется, это тема может быть интересна и тем, кто не заглянет (по религиозным соображениям ) на форум об Обероне.
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.