Текущий архив: 2011.07.31;
Скачать: CL | DM;
Вниз
AfterConstruction, beforedestruction у record Найти похожие ветки
← →
oxffff © (2011-04-06 15:49) [0]Приветствую, всех.
Многи финты С++ основаны на автоматическом вызове деструктора у записей в С++.
Это же создает множество сложностей, которые решаются перегрузкой оператора присваивания, конструктором копий.
Занимаясь развитием своего языка YAR, мне бы не хотелось вводить
перегрузку оператора присваивания и конструктор копий, но тем не менее хотелось бы добавить финты С++.
Ваше мнение о введении AfterConstruction и beforedestruction у записей.
То есть это просто методы не более. В них не нужно ничего освобождать и инициализировать. Если они есть у типа, компилятор проставит их вызовы в начало и конец области видимости экземпляра.
Мне нравится. А что думаете Вы?
← →
Kerk © (2011-04-06 15:54) [1]Указатель на такую запись как будет работать?
← →
oxffff © (2011-04-06 15:58) [2]
> Kerk © (06.04.11 15:54) [1]
> Указатель на такую запись как будет работать?
?
Финализироваться(аналог dispose) с вызовом beforedestruction.
← →
Mystic © (2011-04-06 16:49) [3]Я думаю, что Ada рулит:
http://ada-ru.selfip.org:88/V-0.4w/part_1/ch_14.html
← →
DiamondShark © (2011-04-06 16:51) [4]
> Мне нравится. А что думаете Вы?
Мы думаем, что пора прекратить маяться ерундой по принципу: "С миру по фиче -- голому язык программирования", а начать собирать use case для предполагаемых фич.
Какие у тебя результаты по анализу применения деструкторов записей в С++?
Какие у тебя мысли по поводу того, что в Дельфи они никому в пень не тарахтели?
Если тебе хотелось бы их добавить, значит ты сможешь внятно ответить на вопрос: "С какой целью?".
← →
oxffff © (2011-04-06 17:03) [5]
> Mystic © (06.04.11 16:49) [3]
> Я думаю, что Ada рулит:
> http://ada-ru.selfip.org:88/V-0.4w/part_1/ch_14.html
Почитаю.
← →
han_malign (2011-04-06 17:21) [6]Что-то я не увидел отличий от обычных(C++) конструктора/деструктора...
"Сложности" возникают только при реализации умных указателей(подразумевается любой захват любого ресурса) - и от этого ты никуда и никак не денешься...
З.Ы. Ты еще забыл об explicit...
> Какие у тебя мысли по поводу того, что в Дельфи они никому в пень не тарахтели?
- ну просто абсолютно не нужны - каждый обязан явно инициализировать и зачищать статически размещенные структуры - если он этого не делает - то сам себе кретин...
← →
Kerk © (2011-04-06 17:38) [7]Не удобнее ли в таких случаях классы использовать?
← →
DiamondShark © (2011-04-06 17:52) [8]
> han_malign (06.04.11 17:21) [6]
> - ну просто абсолютно не нужны - каждый обязан явно инициализировать
> и зачищать статически размещенные структуры - если он этого
> не делает - то сам себе кретин...
Можешь без истерик объяснить, зачем нужны неявно инициализированные структуры?
О том, что члены с управляемым временем жизни инициализируются и финализируются в Дельфи автоматически, ты, судя по твоему коменту, вообще не знал.
← →
han_malign (2011-04-06 18:13) [9]
> Можешь без истерик
- я просто подстраиваюсь под вашу безапелляционную риторику.
> О том, что члены с управляемым временем жизни инициализируются
> и финализируются в Дельфи автоматически, ты, судя по твоему
> коменту, вообще не знал.
- ну надо же...
Что и TRTLCriticalSection - тоже? Ну или хотя бы TCriticalSection? Или временем жизни этой и подобных структур не надо управлять?
← →
Kerk © (2011-04-06 18:19) [10]
> han_malign (06.04.11 18:13) [9]
Типы с управляемым временем жизни - это не те, временем жизни которых нужно управлять.
← →
TUser © (2011-04-06 19:53) [11]
> Kerk © (06.04.11 17:38) [7]
>
> Не удобнее ли в таких случаях классы использовать?
>
Имхо: классы, в том виде, в каком они нам известны в Delphi, смущают громоздкостью. Потому как это не просто запись, а конструктор, который при создании вызывает смотрите сколько кода. Поэтому, если я пишу, допустим, текстовый редактор, то каждая буква у меня не будет объектом, хотя, возможно, это и идеологически правильно с точки зрения ООП (объект реального мира = объект в программе).
С этой точки зрения проще расширяемый record с возможностью добавить еще и методы. То есть наследование, инкапсуляция - пож-та, но без лишних тормозов. Насколько я понимаю, это реализовано в Обероне и старших версиях Делфи.
Наследование и инкапсуляция - понятия программы, а не реального мира. В рантайме совершенно неважно вызывается ли виртуальный метод через таблицу оных, или прописанный в коде обычный метод. Лишь бы вызывался. Виртуальность просто позволяет писать меньше кода, но это интерес программиста, а не объективной реальности. Поэтому наследование и инкапсуляция должны быть поняты и полностью обработаны на этапе компиляции, то есть
Taaa = record
N: integer;
end;
Tbbb = record (Taaa)
procedure inc;
end;
должно быть эквивалентно
Tbbb = record
N: integer;
end;
Pbbb = ^Tbbb;
procedure inc (bbb: Pbbb);
Имхо, разумеется.
← →
TUser © (2011-04-06 19:55) [12]
> Потому как это не просто запись, а конструктор, который
> при создании вызывает смотрите сколько кода.
Читать так: не просто запись, а еще и таблица виртуальный методов, конструктор, деструктор и бог весть сколько ассемблерного и неассемблерного кода, который занимается размещением объекта в памяти и бог весть чем еще. Поэтому, стремно создавать отдельный объект на каждый чих.
← →
Kerk © (2011-04-06 20:11) [13]
> Имхо: классы, в том виде, в каком они нам известны в Delphi,
> смущают громоздкостью. Потому как это не просто запись,
> а конструктор, который при создании вызывает смотрите сколько
> кода. Поэтому, если я пишу, допустим, текстовый редактор,
> то каждая буква у меня не будет объектом, хотя, возможно,
> это и идеологически правильно с точки зрения ООП (объект
> реального мира = объект в программе).
Не спорю, но предложение сабжевое ведь в том, что "давайте добавим к записям смотрите сколько кода". Получаются те же классы, только без наследования.
← →
Ega23 © (2011-04-06 20:19) [14]Да и не так уж у класса много кода...
← →
_Юрий (2011-04-06 20:52) [15]
>TUser ©
> то каждая буква у меня не будет объектом
Жалко по 4 лишних байта на букву? Около 20 мегабайт при загрузке "войны и мира" и гигабайтах оперативки ?)
← →
Ega23 © (2011-04-06 21:11) [16]
> Поэтому, если я пишу, допустим, текстовый редактор, то каждая
> буква у меня не будет объектом
А буква и не должна быть объектом, объектом должен быть Token. А это либо символ, либо совокупность символов (слово), либо ещё какая-нить фигня, типа управляющих символов.
← →
TUser © (2011-04-06 21:19) [17]
> А буква и не должна быть объектом, объектом должен быть
> Token.
от задачи зависит
← →
DiamondShark © (2011-04-06 22:02) [18]
> han_malign (06.04.11 18:13) [9]
> я просто подстраиваюсь
И так и не ответил на вопрос: "Зачем нужны неявно инициализированные структуры"?
> Что и TRTLCriticalSection - тоже? Ну или хотя бы TCriticalSection?
> Или временем жизни этой и подобных структур не надо управлять?
Во-первых, > Kerk © (06.04.11 18:19) [10]
Во-вторых, чисто так, ради интереса: много у тебя TRTLCriticalSection со временем жизни в процедуру?
Ты, когда "просто подстраиваешься", голову выключаешь?
← →
Kerk © (2011-04-06 22:08) [19]Просветите меня по поводу записей, я все еще на старых Delphi сижу.
Вот раньше можно было делать что-то типа:TSomeRec = record (или packed record)
A, B: Integer
end;
...
var
SomeRecFile = file of TSomeRec;
...
//ну дальше понятно
А что теперь будет, если я в эту запись засуну метод?
← →
Германн © (2011-04-06 22:14) [20]
> А что теперь будет, если я в эту запись засуну метод?
>
Имхо то же самое.
← →
Игорь Шевченко © (2011-04-06 22:27) [21]например, будет вот так:
THSDateRangeRec = record
public
DateFrom: TDateTime;
DateTill: TDateTime;
function IsValid (EmptyAllowed: Boolean): Boolean;
function ContainsDate (const Value: TDateTime): Boolean;
end;
{ THSDateRangeRec }
function THSDateRangeRec.ContainsDate(const Value: TDateTime): Boolean;
begin
Result := (DateFrom <= Value) and (Value <= DateTill);
end;
function THSDateRangeRec.IsValid(EmptyAllowed: Boolean): Boolean;
begin
if not EmptyAllowed then
Result := (DateFrom <> 0) and (DateTill <> 0) and (DateFrom <= DateTill)
else
Result := (DateFrom = 0) or (DateTill = 0) or (DateFrom <= DateTill);
end;
← →
Kerk © (2011-04-06 22:36) [22]
> Игорь Шевченко © (06.04.11 22:27) [21]
Вопрос был не об этом :)
Вопрос в том, что будет сfile of THSDateRangeRec
← →
Игорь Шевченко © (2011-04-06 22:38) [23]
> Вопрос в том, что будет с file of THSDateRangeRec
Все хорошо будет с файлом. Два поля в каждой записи
← →
Kerk © (2011-04-06 22:41) [24]Ясно, значит методы игнорируются. А SizeOf(THSDateRangeRec) что вернет?
← →
Игорь Шевченко © (2011-04-06 22:50) [25]
> Ясно, значит методы игнорируются. А SizeOf(THSDateRangeRec)
> что вернет?
Как и следует ожидать
← →
DiamondShark © (2011-04-07 01:26) [26]Турбопаскалевский object живее всех живых.
← →
oxffff © (2011-04-07 09:24) [27]RAII
http://blog.barrkel.com/2010/01/one-liner-raii-in-delphi.html
Но создавать еще два дополнительных объекта для финализации накладно.
← →
Компромисс (2011-04-07 12:10) [28]Насчет символов в качестве объектов:
A classic example usage of the flyweight pattern is the data structures for graphical representation of characters in a word processor. It might be desirable to have, for each character in a document, a glyph object containing its font outline, font metrics, and other formatting data, but this would amount to hundreds or thousands of bytes for each character. Instead, for every character there might be a reference to a flyweight glyph object shared by every instance of the same character in the document; only the position of each character (in the document and/or the page) would need to be stored internally.
http://en.wikipedia.org/wiki/Flyweight_pattern
← →
jack128_ (2011-04-07 13:53) [29]
> http://blog.barrkel.com/2010/01/one-liner-raii-in-delphi.
> html
> Но создавать еще два дополнительных объекта для финализации
> накладно
можно обойтись одним.
← →
Kerk © (2011-04-07 13:54) [30]
> oxffff © (07.04.11 09:24) [27]
По-моему, оно читаемости только вредит.
← →
jack128_ (2011-04-07 14:05) [31]
> По-моему, оно читаемости только вредит.
в том виде, который по ссылке - конечно вредит.
а так:var
Obj: TMyObject;
begin
Obj := TMyObject.Create(...);
Obj.AutoDestroy();
....
end;
или так:var
Obj: TSharedPtr<TMyObject>;
begin
Obj := TMyObject.Create(...);
Obj.Value.SameMethod();
....
end;
?
← →
Kerk © (2011-04-07 14:23) [32]Все-таки, если в Delphi нет сборщика мусора, стоит с этим смириться, а не пытаться ковылять на костылях. IMHO.
← →
Sapersky (2011-04-07 14:40) [33]Ну как сказать, те же автоматически финализируемые типы есть.
Теоретически можно прикрутить этот же механизм (с возможностью выбора - ручное/автоосвобождение) к обычным классам. Вроде бы принципиальных препятствий нет... или я не вижу?
Copy-on-write и прочих изощрений не надо, просто счётчик ссылок, как у дин. массива.
В общем, конечно, это не "серебрянная пуля" (опять же, не слышал чтобы сишный аналог - smart_ptr/auto_ptr, или как его там - произвёл какую-то революцию), но было бы приятно.
← →
Sapersky (2011-04-07 14:48) [34]Вроде бы принципиальных препятствий нет
Не считая, конечно, такой мелочи, что прикручивать должен разработчик компилятора/RTL :)
← →
_Юрий (2011-04-07 19:09) [35]
> Все-таки, если в Delphi нет сборщика мусора, стоит с этим
> смириться, а не пытаться ковылять на костылях. IMHO.
может быть, автоматическое уничтожение потомков TInterfacedObject - тоже костыли?
← →
Kerk © (2011-04-07 19:28) [36]А разве нет? Правда тут выбора не было, надо же было как-то работу с COM поддерживать. Вот, например, попробуй положить некоторое количество потомков TInterfacedObject в TObjectList и посмотреть что будет.
TInterfacedObject ведь потомок TObject, правильно? Значит теоретически, он в этот лист должен бы лечь без проблем :)
← →
Игорь Шевченко © (2011-04-07 19:51) [37]
> Вот, например, попробуй положить некоторое количество потомков
> TInterfacedObject в TObjectList и посмотреть что будет.
Бурный смех в зале
← →
_Юрий (2011-04-07 19:56) [38]
> Вот, например, попробуй положить некоторое количество потомков
> TInterfacedObject в TObjectList и посмотреть что будет.
попробуй несколько экземпляров непотомков TInterfacedObject положить в два TObjectList"а.
Или попробуй вызвать memo1.lines.Free;
Кругом одни костыли! Боже как страшно жить
← →
Kerk © (2011-04-07 20:40) [39]
> _Юрий (07.04.11 19:56) [38]
Хорошо, попробуем на примере.
Допустим, у нас есть класс TMyClass. Для чистоты эксперимента специально не сообщаю от чего он наследован и что у него внутри.
Теперь ситуация №1. Мы видим кодvar
MyClass: TMyClass;
begin
//...
MyClass.MyProp.Free;
//...
Здесь не нужно быть семи пядей во лбу, чтобы заподозрить неладное.
Теперь ситуация №2.function TForm1.CreateMyClass: TObject;
begin
Result := TMyClass.Create;
end;
Ответь мне, пожалуйста, в этом коде есть ошибка?
← →
DiamondShark © (2011-04-07 20:41) [40]
> может быть, автоматическое уничтожение потомков TInterfacedObject
> - тоже костыли?
А где есть автоматическое уничтожение потомков TInterfacedObject?
← →
Kerk © (2011-04-07 20:41) [41]
> попробуй несколько экземпляров непотомков TInterfacedObject
> положить в два TObjectList"а.
А почему этого нельзя делать? У TObjectList, если мне не изменяет склероз, в конструкторе есть параметр OwnsObjects, ставишь его в False и клади свои объекты хоть в пять листов.
← →
Kerk © (2011-04-07 20:43) [42]
> DiamondShark © (07.04.11 20:41) [40]
>
> > может быть, автоматическое уничтожение потомков TInterfacedObject
> > - тоже костыли?
>
> А где есть автоматическое уничтожение потомков TInterfacedObject?
>
Видимо это имеется ввидуfunction TInterfacedObject._Release: Integer;
begin
Result := InterlockedDecrement(FRefCount);
if Result = 0 then
Destroy;
end;
← →
_Юрий (2011-04-07 21:14) [43]
> Теперь ситуация №2.
> function TForm1.CreateMyClass: TObject;
> begin
> Result := TMyClass.Create;
> end;
>
> Ответь мне, пожалуйста, в этом коде есть ошибка?
В этом коде нет ошибки.
Пока мы не начали работать с экземпляром как с интерфейсом, никакой подсчет ссылок не ведется, и опасность "самопроизвольного" разрушения отсутствует напрочь, если ты об этом.
← →
_Юрий (2011-04-07 21:26) [44]
> А почему этого нельзя делать? У TObjectList, если мне не
> изменяет склероз, в конструкторе есть параметр OwnsObjects,
> ставишь его в False и клади свои объекты хоть в пять листов.
>
>
По умолчанию параметр равен true. Забыть можно.
А если система большая и связи сложные, и один инстанс регистрируется в разных листах, иной раз вовремя его убить, чтобы никто не обломался позже, становится и вовсе нетривиальной задачей. Решабельной, но требующей дополнительных телодвижений и дополнительного кода. Кстати в таком случае использование механизма саморазрушения является неплохим выходом - мы вообще перестаем заботиться о разрушении, и он гарантинрованно не разрушится, пока о нем хоть кто-то помнит.
Чего в этом плохого?
← →
Kerk © (2011-04-07 21:31) [45]
> _Юрий (07.04.11 21:14) [43]
А ты проверь, чему будет равен RefCount у возвращенного такой функцией объекта (подразумеваем, что он унаследован от TInterfacedObject). Могу сразу сказать, он будет равен нулю.
← →
_Юрий (2011-04-07 21:48) [46]
> Могу сразу сказать, он будет равен нулю.
Ну да, будет равен нулю, это совершенно правильно. На него отсутствуют ссылки как на интерфейс. И он не разрушится, несмотря на RefCount = 0.
Собственно, все написано в его коде.
← →
Kerk © (2011-04-07 22:07) [47]
> _Юрий (07.04.11 21:48) [46]
>
> > Могу сразу сказать, он будет равен нулю.
>
> Ну да, будет равен нулю, это совершенно правильно. На него
> отсутствуют ссылки как на интерфейс. И он не разрушится,
> несмотря на RefCount = 0.
> Собственно, все написано в его коде.
Я не обсуждаю то, что у него в коде написано. В коде ошибок нет, само его существование - ошибка.
Видимо, я действительно слишком издалека зашел.
Вот тебе более конкретный пример, нажми на Button1 более одного раза, посмотри что будет. Закрой форму, посмотри что будет.unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
IMyInterface = interface
["{F63315C6-BCF8-435D-86BB-6271FD9D5C93}"]
function GetStr: string;
end;
TMyClass = class(TInterfacedObject, IMyInterface)
public
function GetStr: string;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
Obj: TObject;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
MyIntf: IMyInterface;
begin
if Supports(Obj, IMyInterface, MyIntf) then
ShowMessage(MyIntf.GetStr);
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Obj.Free;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Obj := TMyClass.Create;
end;
{ TMyClass }
function TMyClass.GetStr: string;
begin
Result := "123";
end;
end.
← →
Kerk © (2011-04-07 22:18) [48]Да, первый пример был крайне неудачен. Это у меня голова просто забита своими частностями.
← →
Игорь Шевченко © (2011-04-07 22:20) [49]Давай немножко изменим:
unit main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
IMyIntf = interface
["{CAE63E79-F4F6-4B49-A235-223546249CD7}"]
function GetStr: string;
end;
TFoo = class(TInterfacedObject, IMyIntf)
private
function GetStr: string;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
FObj: IUnknown;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
MyIntf: IMyIntf;
begin
if Supports(FObj, IMyIntf, MyIntf) then
ShowMessage(MyIntf.GetStr);
end;
{ TFoo }
function TFoo.GetStr: string;
begin
Result := "Foo";
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FObj := nil;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FObj := TFoo.Create;
end;
end.
← →
_oxffff (2011-04-08 08:55) [50]
> Kerk © (07.04.11 22:07) [47]
Я перепишу твой пример до более короткого.
procedure Kill(intf:IUnknown);
begin
end;
procedure TForm5.Button1Click(Sender: TObject);
var obj:TInterfacedObject;
begin
obj:=TInterfacedObject.create;
Kill(obj);
obj.ToString; // <-
end;
← →
reonid © (2011-04-08 11:27) [51]2Kerk ©
>В коде ошибок нет, само его существование - ошибка.
Для объекта (точнее, переменной типа объект, т.е. объектной ссылки!)
вовсе не является ошибкой существование с RefCount = 0.
Более того, наоборот, скорее всего будет ошибкой RefCount <> 0.
← →
_Юрий (2011-04-08 18:57) [52]
> Kerk © (07.04.11 22:07) [47]
> Вот тебе более конкретный пример
Есть некотоыре базовые вещи, которые программист на delphi знать обязан. Например, что созданный объект надо разрушить.
Или например то, что ручное разрушение объекта, который был уже запрошен как интерфейс - это хождение по минному полю. И дело тут не в том, как он реализован - с авторазрущением или без (ничто не мешает нам перекрыть _Release и не разрушать объект при обнулении счетчика). Дело в том, что любая забытая где-либо интерфейсная ссылка на этот объект приведет к проблемам при финализации, если объект уже разрушен руками.
Надо просто понимать, что делаешь
← →
Kerk © (2011-04-08 19:09) [53]
> _Юрий (08.04.11 18:57) [52]
У тебя универсальный подход к любой кривизне: "надо просто ее учитывать и проблем не будет". Ну флаг в руки, чего еще сказать :)
← →
Игорь Шевченко © (2011-04-08 19:17) [54]
> У тебя универсальный подход к любой кривизне: "надо просто
> ее учитывать и проблем не будет".
во-первых, весьма, кстати, разумный подход. во-вторых, а в чем кривизна ?
← →
Kerk © (2011-04-08 19:25) [55]
> Игорь Шевченко © (08.04.11 19:17) [54]
>
> > У тебя универсальный подход к любой кривизне: "надо просто
> > ее учитывать и проблем не будет".
>
> во-первых, весьма, кстати, разумный подход.
Ну да. Жри, что дают.
С реальностью я сам не спорю, что не мешает мне ее критиковать.
> во-вторых, а в чем кривизна ?
Кривизна в том, что интерфейсы к Delphi были прикручены сбоку специально для поддержки COM и для других применений мало приспособлены. В [47] в классическом ООПшном смысле ошибок нет. Тем не менее, имеем что имеем.
← →
_Юрий (2011-04-08 19:26) [56]
> Kerk © (08.04.11 19:09) [53]
У меня есть знакомый прогрммист, который утверждает, что XML - отвратительно неудобный отстой, и в него очень неудобно записывать данные. Потому что легко запутаться и нарушить структуру докумена, забыв например закрывающий тег.
Расследование показало, что он формирует содержимое руками, по типу
StringList.Add("<" + val1 + ">" + val12 + "<" + va1 + "/>");
StringList.SaveToFile(filename);
Думаешь, мне удалось ему что-либо доказать?
← →
Kerk © (2011-04-08 19:31) [57]
> _Юрий (08.04.11 19:26) [56]
Я понимаю, что ты 110% уверен в своей правоте, но ты пытался хотя бы задуматься о том, что я говорю?
← →
_Юрий (2011-04-08 19:39) [58]
> Kerk © (08.04.11 19:31) [57]
Ты отчасти прав. В делфи эта кухня действительно реализована отвратительно. А в том, что это нельзя использовать нигде кроме COM, ты не прав. Использовать можно и нужно, потому, что ничего другого судя по всему не будет, а интерфейсы даже в таком виде способны прекрасно помочь.
← →
Kerk © (2011-04-08 19:45) [59]
> _Юрий (08.04.11 19:39) [58]
Дык чего ж мы тогда спорим. Тут мне возразить нечему.
← →
reonid © (2011-04-08 19:45) [60]2Kerk © (08.04.11 19:25) [55]
Довольно просто было бы реализовать интерфейсы без автоматического уничтожения.
И обязать всех программистов вручную вызывать _AddRef и _Release,
как это реализовано в некоторых языках.
Это не составляет никакой технической трудности.
И все Ваши претензии были бы удовлетворены.
Вопрос, стало бы от этого меньше проблем?
← →
_Юрий (2011-04-08 19:47) [61]
> Kerk © (08.04.11 19:45) [59]
Да, забавно )
← →
DiamondShark © (2011-04-08 19:48) [62]
> Kerk © (08.04.11 19:25) [55]
Вот тебе более конкретный пример, посмотри что будет.
var
x, y: Integer;
begin
x := 2147483647;
y := x + 1;
writeln(y);
end.
Кривизна в том, что целые числа к Delphi были прикручены сбоку специально для поддержки CPU и для других применений мало приспособлены. В классическом арифметическом смысле ошибок нет. Тем не менее, имеем что имеем.
← →
_Юрий (2011-04-08 19:52) [63]
> reonid © (08.04.11 19:45) [60]
> Вопрос, стало бы от этого меньше проблем?
Тут проблема в другом - в том, что программиста вообще заставляют реализовывать эти три метода, в то время как ему нужен только прикладной четвертый метод.
Я вот хочу, чтобы все объекты отдавали мне например DisplayName: string;
И при чем тут еще три метода?
Грубо говоря, класс должен тут же ответить на вопрос - а "Как я буду разрушаться? Автоматически или нет?"
А сам класс этого в общем случае не знает. Это скорее всего знает тот, кто инстанцирует.
А тут получается наоборот - на этот вопрос отвечает класс, а инстанцирующий сдедовательно должен оьязательно знать о деталях реализации интерфейса, получаем нарушение инкапсуляции.
Как то так
← →
Kerk © (2011-04-08 19:55) [64]Удалено модератором
← →
Kerk © (2011-04-08 19:58) [65]
> _Юрий (08.04.11 19:52) [63]
Да, счетчик ссылок не всегда нужен. Тут примером может выступать TComponent, где счетчик ссылок работает иначе.
← →
reonid © (2011-04-08 20:06) [66]2_Юрий (08.04.11 19:52) [63]
Можно было бы сделать и такую реализацию интерфейсов.
Без управляемого времени жизни.
С пустым базовым интерфеисом, от которого бы наследовался IUnknown.
И с СОМом работать, не забывая вручную вызывать _AddRef и _Release.
То, что сделали не так, это было осознанное решение с целью минимизации геморроя.
← →
DiamondShark © (2011-04-08 20:09) [67]
> Kerk © (08.04.11 19:55) [64]
Надеюсь, ты отдаёшь себе отчёт, что практически любую языковую фичу можно использовать нештатным образом.
Объясни, пожалуйста, почему в одном случае ты это считаешь кривизной (языка, а не собственных рук), а в другом -- нет. У тебя ФГМ?
← →
_Юрий (2011-04-08 20:15) [68]
> reonid © (08.04.11 20:06) [66]
Надо было сделать базовый - пустой IInterface, и IUnknown c автоматическим подсчетом ссылок, и наследовать наоборот IUnknown от IInterface.
Тогда было бы все хорошо.
← →
reonid © (2011-04-08 20:23) [69]2_Юрий (08.04.11 20:15) [68]
И получили бы те же грабли, только в профиль.
Запрашиваешь у неуправляемого интерфейса IUnknown,
и всё - объект помер.
← →
_Юрий (2011-04-08 20:28) [70]
> reonid © (08.04.11 20:23) [69]
Ну в общем да, только тогда эти грабли были бы необязательными, потому что необязательно запрашивать IUnknown.
А с нынешним положением дел они обязательные
← →
DiamondShark © (2011-04-08 20:29) [71]
> reonid © (08.04.11 20:23) [69]
По крайней мере, можно было бы чётко разделить COM-овские интерфейсы, и внутренние интерфейсы.
← →
reonid © (2011-04-08 20:37) [72]2DiamondShark © (08.04.11 20:29) [71]
Сейчас хотя бы на глаз легко отличить ob: TMyObject от intf: IMyInterface
А так поди, догадайся, какой из intf1: IMyInterface1 и intf2: IMyInterface2
управляемый, а какой - нет.
← →
reonid © (2011-04-08 20:39) [73]Не говоря уж, что небольшой заменой кода можно легко преобразовать
один тип поведения в другой (добавив в список предков IUnknown, или убрав),
и получить довольно непредсказуемые последствия.
← →
DiamondShark © (2011-04-08 20:51) [74]
> reonid © (08.04.11 20:37) [72]
Сейчас приходится помнить гораздо больше вещей.
> reonid © (08.04.11 20:39) [73]
Изменением предка вообще можно чудес натворить.
Радикальное решение -- только полностью управляемые языки.
В гибридных языках всегда будет что-то выпирать.
← →
Kerk © (2011-04-08 21:46) [75]
> DiamondShark ©
По последним постам вижу, что наконец до тебя дошло о чем речь. Поздравляю. Так бы сразу.
← →
DiamondShark © (2011-04-08 22:42) [76]Удалено модератором
← →
Димка На (2011-04-09 21:26) [77]При присваивании записи она должна вновь инициализироваться?
← →
oxffff © (2011-04-10 12:51) [78]
> Димка На (09.04.11 21:26) [77]
> При присваивании записи она должна вновь инициализироваться?
>
Нет. Это не инициализатор, и не финализатор.
← →
Дмитрий С © (2011-04-11 08:44) [79]
> Нет. Это не инициализатор, и не финализатор.
А что тогда? в чем предназначение?
← →
_oxffff (2011-04-11 09:50) [80]
> Дмитрий С © (11.04.11 08:44) [79]
>
> > Нет. Это не инициализатор, и не финализатор.
>
> А что тогда? в чем предназначение?
Это события экземпляра типа, о том что экземпляр аллокировался и о том, что экземпляр разрушается.
← →
DiamondShark © (2011-04-11 11:04) [81]
> _oxffff (11.04.11 09:50) [80]
И кому они нужны?
← →
oxffff © (2011-04-11 12:21) [82]
> DiamondShark © (11.04.11 11:04) [81]
>
> > _oxffff (11.04.11 09:50) [80]
>
> И кому они нужны?
Тебе.
← →
DiamondShark © (2011-04-11 12:32) [83]
> oxffff © (11.04.11 12:21) [82]
Зачем?
← →
_oxffff (2011-04-11 14:10) [84]
> DiamondShark © (11.04.11 12:32) [83]
>
> > oxffff © (11.04.11 12:21) [82]
>
> Зачем?
Затем.
← →
DiamondShark © (2011-04-11 14:24) [85]Содержательно, чо.
← →
Mystic © (2011-04-11 19:21) [86]> И кому они нужны?
В основном создание всяких трюков, основанных на неявном гарантированном вызове некоторого кода по выходу из области видимости. Что хорошо при работе со всяким API. Например,
type
THandle = record
Value: THandle;
procedure Initialize();
procedure Finalize();
end;
procedure THandle.Initialize();
begin
Value := 0;
end;
procedure THandle.Finalize();
begin
if (Value <> 0) and (Value <> INVALID_HANDLE_VALUE) then
CloseHandle(Handle);
end;
В результате чего, определив один раз Handle нам больше не надо заботиться о том, что мы забыли его закрыть, и писать каждый раз try/finally.
А переопределив Adjust мы вообще можем перестать следить и за копированием:
procedure THandle.Adjust();
begin
if Handle = 0 then Exit;
DuplicateHandle(
SourceProcessHandle => GetCurrentProcess(),
SourceHandle => Handle,
TargetProcessHandle => GetCurrentProcess(),
TargetHandle => Handle,
DesiredAccess => 0,
InheritHandle => False,
Options => DUPLICATE_SAME_ACCESS
);
end;
← →
DiamondShark © (2011-04-11 20:51) [87]
> Mystic © (11.04.11 19:21) [86]
Это очень классный пример, но какую долю кода составляют подобные трюки?
Я предлагал автору провести анализ использования.
Знаете, можно наковырять стопицот "всяких трюков", под которые можно затребовать новую фичу языка.
Стоит ли овчинка выделки, если эти трюки составляют сотую долю процента кода, написанного на этом языке? Ну, допустим, автору ветки по барабану, у него один сам себе разработчик и ноль пользователей. А для сколь-нибудь реального языка?
← →
_Юрий (2011-04-11 21:06) [88]
> DiamondShark © (11.04.11 20:51) [87]
> но какую долю кода составляют подобные трюки?
Неявный гарантированый финализатор - на мой взгляд, это должно быть реализовано на уровне языка, а не трюком, потому что это нужно постоянно и везде.
← →
oxffff © (2011-04-11 21:19) [89]
> Я предлагал автору провести анализ использования.
Выше я уже написал о RAII.
> Стоит ли овчинка выделки,
Ну подставить вызовы в цикле по слотам scope при enter scope и leave scope это можно сказать бесплатно.
← →
Mystic © (2011-04-11 22:05) [90]
> Это очень классный пример, но какую долю кода составляют
> подобные трюки?
Если код работает с низкоуровневым API, то очень большой. И, что хуже, является причиной трудноуловимых ликов.
Ну а в целом пример заимствован из языка Ada, там он востребован :)
← →
DiamondShark © (2011-04-12 01:23) [91]
> oxffff © (11.04.11 21:19) [89]
> это можно сказать бесплатно.
Посмотрим, сколько стоит "бесплатно".
0. Локальная переменная в инициализаторе
procedure TMyAutoRecord.AfterConstruction
var
A: TMyAutoRecord;
begin
//
end;
Что делать с бесконечной рекурсией?
1. Копирование.
var
A, B: TMyAutoRecord;
begin
//...
A := B;
//...
end;
Что произойдёт со старым значением A? Вызывать ли финализатор?
Что произойдёт при выходе из видимости двух идентичных копий? Два вызова финализатора, очевидно. И нет никакой возможности в финализаторе определить, что копия значения уже была финализирована. Как собираемся документировать такое поведение?
2. Копирование в поле объекта.
Всё то же самое, плюс инициализация в конструкторе и финализация в деструкторе.
3. Динамическое распределение.
type
PMyAutoRecord = ^TMyAutoRecord;
var
A : PMyAutoRecord;
begin
new(A);
dispose(A);
end;
Вызов инициализатора вnew
и финализатора вdispose
.
4. Разные способы передачи параметра
procedure Bar(A: TMyAutoRecord);
procedure Bar(var A: TMyAutoRecord);
procedure Bar(const A: TMyAutoRecord);
procedure Bar(out A: TMyAutoRecord);
function Foo: TMyAutoRecord;
Скажи навскидку, какое поведение будет реализовано в каждом случае?
Теперь реализуй и задокументируй.
"Бесплатно", блин. А без перекрытия операции копирования ещё и принципиально глюкаво.
← →
DiamondShark © (2011-04-12 01:44) [92]
> хотелось бы добавить финты С++.
Хм, финты...
You should not construct two auto_ptr<Type> objects that own the same object.
Т.е. в С++ те же самые проблемы с корректным копированием. И это несмотря на возможность перекрытия копирования!
А оно надо -- повторять чужие грабли?
← →
Mystic © (2011-04-12 01:51) [93]
> DiamondShark © (12.04.11 01:23) [91]
1. Я же писал, есть метод Adjust, который вызывается в случае копирования. Итого на строке A := B вызовется
A.Finalize();
внутренняя функция копирования
A.Adjust();
При этом компилятор считает, что Initialize + Finalize = 0 (сокращается), поэтому если мы видим, что A до этого не использовалось, то эти методы не дергаются.
Если метод Adjust неопределен, то копирование запрещено.
2. А тут что за проблемы? Скопировали и забыли :)
3. Аналогично. Вызвали New, вызвался Initialize. Вызвался Dispose, вызвался Finalize.
4.
procedure Bar(A: TMyAutoRecord);
Копирование параметра, строго говоря, Initialize, Finalize, копирование + Adjust. Initialize + Finalize = 0, поэтому сокращается до копирование + Adjust.
procedure Bar(var A: TMyAutoRecord);
Очевидно ничего
procedure Bar(const A: TMyAutoRecord);
Очевидно ничего, разновидность var
procedure Bar(out A: TMyAutoRecord);
Очевидно ничего, разновидность var
function Foo: TMyAutoRecord; = procedure(var Result: TMyAutoRecord);
← →
_oxfffff (2011-04-12 10:27) [94]
> DiamondShark © (12.04.11 01:23) [91]
>
> > oxffff © (11.04.11 21:19) [89]
> > это можно сказать бесплатно.
>
> Посмотрим, сколько стоит "бесплатно".
>
> 0. Локальная переменная в инициализаторе
>
> procedure TMyAutoRecord.AfterConstruction
> var
> A: TMyAutoRecord;
> begin
> //
> end;
>
> Что делать с бесконечной рекурсией?
1. А что делать с остальной бесконечной рекурсией в программах?
2. Hint компилятора.
← →
Дмитрий С © (2011-04-12 10:35) [95]А практическая значимость?
← →
oxffff © (2011-04-12 10:36) [96]
> function Foo: TMyAutoRecord; = procedure(var Result: TMyAutoRecord);
Не всегда.
← →
oxffff © (2011-04-12 10:37) [97]
> Дмитрий С © (12.04.11 10:35) [95]
> А практическая значимость?
Нормально реализовать
http://blog.barrkel.com/2010/01/one-liner-raii-in-delphi.html
http://blog.barrkel.com/2008/09/smart-pointers-in-delphi.html
← →
oxffff © (2011-04-12 10:39) [98]
> oxffff © (12.04.11 10:36) [96]
>
> > function Foo: TMyAutoRecord; = procedure(var Result: TMyAutoRecord);
>
>
>
> Не всегда.
В смысле я имею ввиду не только записи.
← →
oxffff © (2011-04-12 10:51) [99]
> DiamondShark © (12.04.11 01:23) [91]
Я не собираюсь повторять аналог семантики С++.
Это просто события, а не семантика финализации, инициализации, копирования.
Также можно добавить событие копирования.
← →
DiamondShark © (2011-04-12 12:54) [100]
> oxffff © (12.04.11 10:51) [99]
И тем не менее, народ собрался юзать именно семантику финализации, инициализации, копирования.
Я же говорю: перед введением фичи надо собирать юзкейсы. И анализировать частоту использования. Это резко снижает затраты на реализацию багофич.
Если тебе не надо копировать семантику Ц++, введи в язык просто типизированные смартпоинтеры с подсчётом ссылок. Реализовать можешь по аналогии с AnsiString: выделять в памяти блок с префиксом счётчика ссылок, поинтер указывает на начало данных. Получаем прозрачную совместимость с обычным поинтером. Это будет полезная вещь.
> http://blog.barrkel.com/2010/01/one-liner-raii-in-delphi.html
Чушь собачья.
← →
Дмитрий С © (2011-04-12 19:35) [101]
> Чушь собачья.
Согласен, как и идея "программирование для программирования".
← →
_Юрий (2011-04-12 20:08) [102]
> Чушь собачья.
>
Очень удобно для случаев, когда блок финализации должен быть выполнен или не выполнен в зависимости от условий, определяемых в середине скоупа
← →
DiamondShark © (2011-04-12 20:17) [103]
> _Юрий (12.04.11 20:08) [102]
Вся беда только в том, что по ссылке -- безусловная финализация в конце скопа.
← →
oxffff © (2011-04-12 20:21) [104]
> > http://blog.barrkel.com/2010/01/one-liner-raii-in-delphi.
> html
>
> Чушь собачья.
Довольно смело, но странно осуждать идею инженера компилятора Delphi.
Ну, как говорится, сколько людей, столько и мнений.
← →
_Юрий (2011-04-12 20:29) [105]
> DiamondShark © (12.04.11 20:17) [103]
>
>
Она безусловна после того, как ее инициализировали. Ее можно инициализировать по условию
← →
DiamondShark © (2011-04-13 01:40) [106]
> oxffff © (12.04.11 20:21) [104]
> Довольно смело, но странно осуждать идею инженера компилятора Delphi.
Ох ты ж ЁТНХ. Инженер компилятора Delphi малость слоупок. Этой идеей пользовались с тех пор, как в Delphi появились интерфейсы, т.е. так примерно лет 15 уже. Идея бродила в этом вашем фидо ещё когда "инженер компилятора Delphi" тёлок за косички дёргал и получал томом английской грамматики по башке.
Сам пользовался ещё в delphi 3, потом забил: возни много, толку мало.
Вердикт "Чушь собачья" является не мнением, а фактом, проверенным временем.
> Ну, как говорится, сколько людей, столько и мнений.
А Истина -- одна.
← →
oxffff © (2011-04-13 09:34) [107]
> DiamondShark © (13.04.11 01:40) [106]
А что же это за идея такая? Можно код.
← →
DiamondShark © (2011-04-13 11:54) [108]
> oxffff © (13.04.11 09:34) [107]
Пил вчера?
← →
oxffff © (2011-04-13 12:15) [109]
> DiamondShark © (13.04.11 11:54) [108]
>
> > oxffff © (13.04.11 09:34) [107]
>
> Пил вчера?
Нет. Ты код давай.
← →
DiamondShark © (2011-04-13 13:27) [110]
> oxffff © (13.04.11 12:15) [109]
Прикольный получается диалог:
-- Вот идея инженера компилятора Delphi.
-- Этой идее уже 15 лет.
-- А что же это за идея такая?
Ты либо пьян, либо толсто тролишь.
← →
_oxffff (2011-04-13 14:44) [111]
> DiamondShark © (13.04.11 13:27) [110]
>
> > oxffff © (13.04.11 12:15) [109]
>
> Прикольный получается диалог:
>
> -- Вот идея инженера компилятора Delphi.
> -- Этой идее уже 15 лет.
> -- А что же это за идея такая?
>
> Ты либо пьян, либо толсто тролишь.
>Сам пользовался ещё в delphi 3, потом забил: возни много, толку мало.
Мне понятна идея инженера, но совершенно не понятна идея, которую ты использовал в Delphi 3.
Вот я прошу код идеи, которую ты использовал в Delphi 3,
с которой ты возился очень долго, а в итоге выхлопа не было.
А то твои намеки о том, что идея инженера эквивалент идеи, которую ты использовал в Delphi 3 мягко говоря плохо пахнут.
← →
jack128_ (2011-04-13 16:27) [112]
> А то твои намеки о том, что идея инженера эквивалент идеи,
> которую ты использовал в Delphi 3 мягко говоря плохо пахнут.
>
абсолютно эквивалентны. принцип один и тот же, автоподсчет ссылок на интерфейс.
← →
DiamondShark © (2011-04-13 16:29) [113]
> _oxffff (13.04.11 14:44) [111]
Поскольку, я не могу поверить, что тебе не понятно слово "эта", то мне остаётся только предположить, что ты в "идее инженера" видишь то, чего там либо нет, либо не видно мне.
Изложи, пожалуйста, своими словами, как ты понял "идею инженера".
← →
oxffff © (2011-04-13 16:44) [114]
> jack128_ (13.04.11 16:27) [112]
>
> > А то твои намеки о том, что идея инженера эквивалент идеи,
>
> > которую ты использовал в Delphi 3 мягко говоря плохо
> пахнут.
> >
>
> абсолютно эквивалентны.
C точки зрения семантики интерфейсов. Согласен.
А с точки зрения In place объявления. Не согласен.
← →
oxffff © (2011-04-13 16:45) [115]
> DiamondShark © (13.04.11 16:29) [113]
Задняя передача?
[112]
← →
DiamondShark © (2011-04-13 17:07) [116]
> А с точки зрения In place объявления. Не согласен.
С точки зрения In place объявления сильно мешало отсутствие анонимных методов с замыканием.
Но у меня было asm-шаманство с указателем на локальную процедуру ;)
Т.е., где-то так:
type
TScopeExitNotifier = class(TInterfacedObject)
private
FProc: Pointer;
public
constructor Create(const AProc: Pointer);
destructor Destroy; override;
end;
constructor TScopeExitNotifier.Create(const AProc: Pointer);
begin
FProc := AProc;
end;
destructor TScopeExitNotifier.Destroy;
begin
if Assigned(FProc) then
asm
// тут шаманство со стеком и вызов локальной процедуры по FProc
end;
inherited;
end;
function MakeScopeExitNotifier(const AProc: Pointer): IInterface;
begin
Result := TScopeExitNotifier.Create(AProc);
end;
asm-шаманство по памяти не воспроизведу.
procedure Main;
procedure ScopeExitProc;
begin
...
end;
begin
MakeScopeExitNotifier(@ScopeExitProc);
...
end;
Без полноценных замыканий стрёмно, конечно.
Но в таком виде оно известно со времён Дельфи3 и вовсю гуляло по федо.
А с замыканиями и я многим старым финтам новую жизнь могу придумать.
← →
_oxffff (2011-04-13 17:19) [117]
> А с замыканиями и я многим старым финтам новую жизнь могу
> придумать.
О том и речь. Это безопасней, чем использование вложенных процедур и функций, в которых запрещено обращение out of inner scope, в противном случае шамаство с ASM становится нетривиальным под каждую процедуру. Ну или полная копия между [esp,ebp] интервалом, что накладно.
Страницы: 1 2 3 вся ветка
Текущий архив: 2011.07.31;
Скачать: CL | DM;
Память: 0.81 MB
Время: 0.01 c