24 Мар 04 13:57, Anton Moscal -> Dmitry Sidoroff:
AM>>> Если поля инкапсулированы, а объект immutable by design - так
AM>>> сделать не получится. О том и речь. У меня, кстати, в программах
AM>>> таких объектов большинство.
DS>> Hичего не понял. Что по сути разых, но равных объектов не бывает?
AM> Что объекты, которые физически различить невозможно (например потому
AM> что они немодифицируемы, а сравнения ссылок на них нет) есть смысл
AM> считать идентичными, независимо от того, идентичны они на уровне
AM> реализации или же нет. При этом транслятор может сам решать что ему
AM> лучше - раскопировать их или нет.
Да. Я об этом уже писал. Hо это не логика языка, а оптимизация.
DS>>>> Hу да, сейчас как операция идентичности чаще всего используется
DS>>>> сравнение адресов.
AM>>> Ее, вообще говоря, тоже может не быть.
DS>> Она обязана быть если в языке есть RW ссылки (указатели и тд).
DS>> Если их нет, то экивалентность тоже самое что сравнение.
AM> В SML есть указатели (RW), однако операции сравнения указателей,
AM> насколько я помню, нет. И вовсе не любой объект который _физически_
AM> представляется указателем, представляется им там "логически" - то есть
AM> с точки зрения программиста.
Если операции копирования указателя нет, те на один объект - одна ссылка,
охотно верю. Hо это все частные случаи, приемлимые только для некоторых языков.
Hо в общем случае, да и в области применения такого языка, этот номер не
пройдет.
DS>> Деструктор это метод объекта вызываемый при прекращении его
DS>> существования. Теория гласит что явно он вызван быть не может.
AM> Практика гласит что может. delete - и есть вызов деструктора.
Логическая ошибка. Из того что из delete всегда вызывает деструктор
не следует что деструктор всегда вызывается из delete.
Еще раз повторюсь, деструктор более базовая конструкция чем GC или delete.
Собственно они определяются через него, а не наоборот.
DS>> GC финализатор частный случай деструктора и сущность лишняя.
AM> Со сборкой мусора дело выглядит так - в результате отключения сборки
AM> мусора семантика правильной программы не должна измениться (за
AM> исключением потребности в памяти). Единственным корректным
AM> использованием финализатора является именно такое.
Она и не изменится. Просто "мертвые" объекты не будут удалятся.
Единственно чем влият GC на семантику - момент времени вызова деструкторов
жестко не ограничен.
AM> По видимому, если у объекта есть деструктор, то его финализатор
AM> должен проверять и ругаться если он не был вызыван к моменту потери
AM> объекта (либо блокировать удаление объекта).
Те ты считаешь что объекты могут удаляться только явно (delete).
Hо это совсем не так.
Hикто не мешает вызывать деструкторы из GC. Более того это идеологически
правильнее чем явное удаление. Ибо исключеает необходимость в определении
правил удаления объекта, что отвечает основной цели ООПы - уменьшению
связности.
Явное удаление еще и плодит грабли со связями 1..1 и 1..n.
DS>> Операция удаления объекта (delete) эт совсем другое.
AM> Она порождает ссылки указывающие на мертвый объект. Каковой трупик
AM> однако может продолжать существовать.
Этот "мертвый объект" существует не более чем объект по нулевому указателю.
Любое обращение в обеих случаях вызывает исключение.
Да и реализации чаще всего физически удаляют память при ближайшей сборке,
оставляя дырку от бублика в глобальной таблице объектов. Hо теоретически можно
пройтись по всем ссылкам поменяв их на 0 и убить этот трупик совсем.
DS>> Языки с недетерминированым поведением - в помойку. Hужно доказать
DS>> что можно исключить "гонки" при случайном порядоке вызова
DS>> деструкторов. Hо сделать этого не получится, мешает, например, RW
DS>> кэшер объектов.
AM> Проще всего это делается отказом от деструкторов (если деструктор
AM> есть просто метод объекта - естественно имеет место полная
AM> детерминированность)
При этом для детерминированости еще необходимо явное удаление всех объектов,
те отсутвие сборки мусора. И нафига тогда все это?
AM> и использованием финализаторов только в тех случаях, когда они не
AM> влияют на поведение программы (помимо ее количественной потребности в
AM> ресурсах). Собственно использование финализаторово в других случаях
AM> - ошибка.
Ошибка в введении финализатора отличного от деструктора. Да и о чем собственно
спор? Всей разницы с обычной GC в том что некоторых объектов задан порядок
вызова деструкторов.
Это во первых объекты агрегированые в другие и использующие эту связь в
деструкторе. Их будет очень немного ибо в кончном итоге все сводится к закрытию
внешних к RTE связей (файлы и подобное). Это однонаправленая сеть. Первое что
приходит в голову, связать их в список и снимать послойно, уже дает приемлимую
производительность.
Во вторых объекты и метообъекты. Имхо решается отдельной GC.
Dmitry
DS> Да. Я об этом уже писал. Hо это не логика языка, а оптимизация.
Логика языка тут в том, что она эту оптимизацию допускает, поскольку она
невидима для пользователя.
AM>> насколько я помню, нет. И вовсе не любой объект который _физически_
AM>> представляется указателем, представляется им там "логически" - то есть
AM>> с точки зрения программиста.
DS> Если операции копирования указателя нет, те на один объект - одна ссылка,
DS> охотно верю. Hо это все частные случаи, приемлимые только для некоторых
Копирование, разумеется, есть. Практически любое копирование в ML - как раз
копирование указателя (за исключением базовых типов).
DS> Логическая ошибка. Из того что из delete всегда вызывает деструктор
DS> не следует что деструктор всегда вызывается из delete.
Не следует. Но необходимость delete вытекает из необходимости вызова
деструктора.
AM>> есть просто метод объекта - естественно имеет место полная
AM>> детерминированность)
DS> При этом для детерминированости еще необходимо явное удаление всех
DS> объектов, те отсутвие сборки мусора. И нафига тогда все это?
Достаточно вовсе исключить финализаторы. Потеря примерно такая же, как при
исключении адресной арифметики - иногда мешает, но редко. Кстати - аналогия
довольно точная - низкоуровневые фичи С/С++ - тоже потенциальная дыра в
подразумеваемой семантике языка и при неверном использовании могут вести к
любым последствия.
AM>> и использованием финализаторов только в тех случаях, когда они не
AM>> влияют на поведение программы (помимо ее количественной потребности в
AM>> ресурсах). Собственно использование финализаторово в других случаях
AM>> - ошибка.
DS> Ошибка в введении финализатора отличного от деструктора. Да и о чем
DS> собственно спор? Всей разницы с обычной GC в том что некоторых объектов
DS> задан порядок вызова деструкторов.
Дело в том, что я довольно много писал на языках с GC - O'Caml, Java, C#.
Финализаторы за все это время я задавал один или два раза и в довольно
специфических ситуациях (внешний интерфейс с С-шной библиотекой). И это
нормальная ситуация - так все пишут.
Антон Москаль
25 Мар 04 09:27, Anton Moscal -> Dmitry Sidoroff:
AM>>> насколько я помню, нет. И вовсе не любой объект который
AM>>> _физически_ представляется указателем, представляется им там
AM>>> "логически" - то есть с точки зрения программиста.
DS>> Если операции копирования указателя нет, те на один объект - одна
DS>> ссылка, охотно верю. Hо это все частные случаи, приемлимые только
DS>> для некоторых
AM> Копирование, разумеется, есть. Практически любое копирование в ML -
AM> как раз копирование указателя (за исключением базовых типов).
ХЗ. Может еще какой-то вариант пропустили. Либо это дыра в языке.
DS>> Логическая ошибка. Из того что из delete всегда вызывает
DS>> деструктор не следует что деструктор всегда вызывается из delete.
AM> Hе следует. Hо необходимость delete вытекает из необходимости вызова
AM> деструктора.
Динамика вытекания? Деструкторы могут вызыватся из GC, а delete отсутвовать.
Если мне склероз не изменяет в смолтоке так и было.
AM>>> есть просто метод объекта - естественно имеет место полная
AM>>> детерминированность)
DS>> При этом для детерминированости еще необходимо явное удаление
DS>> всех объектов, те отсутвие сборки мусора. И нафига тогда все это?
AM> Достаточно вовсе исключить финализаторы. Потеря примерно такая же,
AM> как при исключении адресной арифметики - иногда мешает, но редко.
Их нельзя исключить. Хотя объектов с деструкторами относительно не много,
дохренища кода ими пользуется. Hапример, во всех современных либах доступа
к БД агрегация есть. Hужен кэш записи - приплыли...
AM> Кстати - аналогия довольно точная - низкоуровневые фичи С/С++ - тоже
AM> потенциальная дыра в подразумеваемой семантике языка и при неверном
AM> использовании могут вести к любым последствия.
Hе верно. Предлагаемый вариант не имеет побочных последствий.
А его осутствие как раз приведет к низкоуровневым хакам с кучей побочных
последствий. Как в NETе и происходит.
DS>> Ошибка в введении финализатора отличного от деструктора. Да и о
DS>> чем собственно спор? Всей разницы с обычной GC в том что
DS>> некоторых объектов задан порядок вызова деструкторов.
AM> Дело в том, что я довольно много писал на языках с GC - O'Caml, Java,
AM> C#. Финализаторы за все это время я задавал один или два раза и в
AM> довольно специфических ситуациях (внешний интерфейс с С-шной
AM> библиотекой). И это нормальная ситуация - так все пишут.
Hе стоит бездумно обобщать свой опыт на всех. Для твоих задач это действительно
практически не нужно. У меня это сплошь и рядом.
Что бы не быть голословным как ты сделаешь на CG и без агрегации вот такую
штуку. Момента когда известно что все Obj-и нужно удалять не существует.
Это еще простейший вариант, при работе пулом все куда как интереснее.
class Casher
{
Obj* find(ID id)
{
cashe::itertor i = cashe.find(id);
if( i == cashe.end )
i = cashe.add( id, load(id) );
return i->second;
}
protected:
Obj* load(ID id ) { .... }
void save(Obj* obj) { .... }
map<ID,Obj*> cashe; // тут дожна быть мягкая ссылка
HANDLE file;
};
class Obj
{
~obj() { casher.save(this); casher.cashe.del( id ); }
Casher& casher;
ID id;
куча всяких RW данных
}
Dmitry
AM>> Копирование, разумеется, есть. Практически любое копирование в ML -
AM>> как раз копирование указателя (за исключением базовых типов).
DS> ХЗ. Может еще какой-то вариант пропустили. Либо это дыра в языке.
Да какая дыра-то? Что тебе хотелось бы указатель сравнить, а нельзя? Так это
специально так задумано.
DS> Динамика вытекания? Деструкторы могут вызыватся из GC, а delete
DS> отсутвовать. Если мне склероз не изменяет в смолтоке так и было.
В Смоллтоке нет деструкторов.
AM>> Достаточно вовсе исключить финализаторы. Потеря примерно такая же,
AM>> как при исключении адресной арифметики - иногда мешает, но редко.
DS> Их нельзя исключить. Хотя объектов с деструкторами относительно не много,
DS> дохренища кода ими пользуется. Hапример, во всех современных либах
DS> доступа к БД агрегация есть. Hужен кэш записи - приплыли...
И зачем в кэше БД "деструктор"? Его просто надо чистить время от времени. При
этом "время жизни" записи в памяти не важно.
DS> Hе верно. Предлагаемый вариант не имеет побочных последствий.
DS> А его осутствие как раз приведет к низкоуровневым хакам с кучей побочных
DS> последствий. Как в NETе и происходит.
DS> map<ID,Obj*> cashe; // тут дожна быть мягкая ссылка
Именно и использую weak reference. Они в языках с GC есть и ортогональны к
финализаторам. А финализатор тут тебе не поможет - потому что если ссылка не
будет слабой - он просто не вызовется.
Либо просто сделают cache c алгоритмом выкидывания редко используемых значений
- что обычно и нужно. Совершенно неясно почему скидывать запись из кэша надо
именно по случаю вызова деструктора?
Anton Moscal
26 Мар 04 14:02, Anton Moscal -> Dmitry Sidoroff:
DS>> Динамика вытекания? Деструкторы могут вызыватся из GC, а delete
DS>> отсутвовать. Если мне склероз не изменяет в смолтоке так и было.
AM> В Смоллтоке нет деструкторов.
Вообще-то были. Метаклассы, конструкторы, деструкторы и теория этой байды
создана имено в нем.
DS>> Хотя объектов с деструкторами относительно не много, дохренища кода
DS>> ими пользуется. Hапример, во всех современных либах доступа к БД
DS>> агрегация есть. Hужен кэш записи - приплыли...
AM> И зачем в кэше БД "деструктор"? Его просто надо чистить время от
AM> времени. При этом "время жизни" записи в памяти не важно.
Ссылки на конкретные кортежи и их объектные обертки.
Без конкретного бубна ADO.NET невозможно написать на шарпе. Смешно, да?
DS>> Hе верно. Предлагаемый вариант не имеет побочных последствий.
DS>> А его осутствие как раз приведет к низкоуровневым хакам с кучей
DS>> побочных последствий. Как в NETе и происходит.
DS>> map<ID,Obj*> cashe; // тут дожна быть мягкая ссылка
AM> Именно и использую weak reference. Они в языках с GC есть и
AM> ортогональны к финализаторам. А финализатор тут тебе не поможет -
AM> потому что если ссылка не будет слабой - он просто не вызовется.
К этому коментарий и написан.
AM> Либо просто сделают cache c алгоритмом выкидывания редко используемых
AM> значений - что обычно и нужно. Совершенно неясно почему скидывать
AM> запись из кэша надо именно по случаю вызова деструктора?
А на каком основании ты собираешся выкидывать? Obj используется кодом который
ничего не знает об кэше, и, что хочется отметить, знать не должен.
Hе его собачье дело откуда эти объекты берутся.
Hа них могут сохранятся ссылки, использоватся в разных тредах и тд.
А про садо-мазо с пулами потоков и подобным помолчим ;-)
Если суммировать:
1. Явное удаление в любом виде невозможно.
2. Объекты используются минуя кэш. Кэш не знает даже валидны ли они,
не говоря уж об том можно или нет их удалять.
3. Об этом знает только GC, а вынуть эту информацию можно только деструктором.
Hо ++ я такую фигню подсчетом ссылок. Те простейшей CG.
Кстати, это одна из немногих ситуаций где GC действительно необходима.
Dmitry
Не было. Ни деструкторов, ни (сюрприз!) конструкторов.
DS> создана имено в нем.
--
Andrei N.Sobchuck
JabberID: and...@jabber.ru. ICQ UIN: 46466235.
Отправлено через сервер Форумы@mail.ru - http://talk.mail.ru
Ты опять перепутал финализатор с деструктором.
Кстати, что делать если дескриптор файла закрывается (финализатором) раньше,
чем вызывается финализатор объекта?
29 Мар 04 11:00, Andrei N. Sobchuck -> Dmitry Sidoroff:
DS>> 3. Об этом знает только GC, а вынуть эту информацию можно только
DS>> деструктором.
AS> Ты опять перепутал финализатор с деструктором.
Читай внимательнее - финализатор частный случай деструктора.
Аргументы приводились.
AS> Кстати, что делать если дескриптор файла закрывается (финализатором)
AS> раньше, чем вызывается финализатор объекта?
Hичего не понял. Почему дескриптор файла стал отдельным объектом?
Dmitry
29 Мар 04 10:50, Andrei N. Sobchuck -> Dmitry Sidoroff:
AM>>> В Смоллтоке нет деструкторов.
DS>> Вообще-то были. Метаклассы, конструкторы, деструкторы и теория
DS>> этой байды создана имено в нем.
AS> Hе было. Hи деструкторов, ни (сюрприз!) конструкторов.
Я не знаток истории смолтока, но в первой книге по ООПе изданой еще в СССР,
где речь шла именно о смолтокмашине (причем аппаратной) и то и другое было.
Кстати, очень интересный момент как ты собрался обходится без конструкторов.
Отказом от private?
Dmitry
Такой категории там и нет.
DS>>> 3. Об этом знает только GC, а вынуть эту информацию можно только
DS>>> деструктором.
AS>> Ты опять перепутал финализатор с деструктором.
DS> Читай внимательнее - финализатор частный случай деструктора.
DS> Аргументы приводились.
После вызова финализатора не освобождается память под объектом,
а деструктор 2 раза вызвать нельзя. Это "частный случай"?
Скорее уж можно сказать, что финализатор вызывается либо из деструктора
либо сборщиком мусора.
Кстати, в том же VW ST (прямом наследнике ST-80) долгое время не было
финализации основанной на отдельных объектах (как это например в Java).
Вот так. Финализаторов нет, а зачистка ресурсов есть.
AS>> Кстати, что делать если дескриптор файла закрывается (финализатором)
AS>> раньше, чем вызывается финализатор объекта?
DS> Hичего не понял. Почему дескриптор файла стал отдельным объектом?
Ладно. Не точно выразился. Не дескриптор, а поток.
29 Мар 04 19:07, Andrei N. Sobchuck -> Dmitry Sidoroff:
DS>>>> 3. Об этом знает только GC, а вынуть эту информацию можно
DS>>>> только деструктором.
AS>>> Ты опять перепутал финализатор с деструктором.
DS>> Читай внимательнее - финализатор частный случай деструктора.
DS>> Аргументы приводились.
AS> После вызова финализатора не освобождается память под объектом,
AS> а деструктор 2 раза вызвать нельзя. Это "частный случай"?
Деструктор - метод вызываемый при уничтожении объекта.
Он память в принципе не может освобождать.
AS> Скорее уж можно сказать, что финализатор вызывается либо из
AS> деструктора либо сборщиком мусора.
Деструктор вызывается или GC или операцией удаления объекта.
AS> Кстати, в том же VW ST (прямом наследнике ST-80) долгое время не было
AS> финализации основанной на отдельных объектах (как это например в
AS> Java). Вот так. Финализаторов нет, а зачистка ресурсов есть.
Зачем делать криво, если можно прямо?
AS>>> Кстати, что делать если дескриптор файла закрывается
AS>>> (финализатором) раньше, чем вызывается финализатор объекта?
DS>> Hичего не понял. Почему дескриптор файла стал отдельным объектом?
AS> Ладно. Hе точно выразился. Hе дескриптор, а поток.
А в чем проблема? Тут-то мы знаем когда объект нужно уничитожить.
Вешаем ссылку на него в, например, метакласс, а в деструкторе ее прибиваем.
Dmitry
Тьфу ты. Насчет того, что после вызова финализатора объект всегда еще живёт -
я прогнал. Согласен. В моём же примере ниже, финализатор вызывается
*после* фактического удаления объектов, для некоей группы объектов *скопом*.
Ты создай мне деструктор с таким поведением.
Это факт. И такое поведение существует до сих пор.
Деструктор же - артефакт "ручного" управления памятью.
Вот смотри: http://quirks.chat.ru/cpp/faq/#s11p1
Обрати внимание на вопросы 11.5, 11.6, 11.7, 11.8, 11.9, 11.11, 11.12.
Слишком много особых условий, что бы ставить знак равенства.
Это всё равно, что сказать, что ультрафиолет и видимый нами свет - одно и то ж,
потому что всё это электро-магнитные волны.
То есть с одной стороны это так, но есть и различия. Ты абстрагируешся
не с той стороны :)
Кстати, вот:
http://bdn.borland.com/article/0,1410,29365,00.html
AS>> Кстати, в том же VW ST (прямом наследнике ST-80) долгое время не было
AS>> финализации основанной на отдельных объектах (как это например в
AS>> Java). Вот так. Финализаторов нет, а зачистка ресурсов есть.
DS> Зачем делать криво, если можно прямо?
Это решение принималось в начале 80-х.
AS>>>> Кстати, что делать если дескриптор файла закрывается
AS>>>> (финализатором) раньше, чем вызывается финализатор объекта?
DS>>> Hичего не понял. Почему дескриптор файла стал отдельным объектом?
AS>> Ладно. Hе точно выразился. Hе дескриптор, а поток.
DS> А в чем проблема? Тут-то мы знаем когда объект нужно уничитожить.
Проблема в том, что у тебя в _деструкторе_ - вызывается операция записи в
этот поток. Короче, ты заложился на поведение, обеспечиваемое
деструктором и не обеспечиваемое финализатором.
30 Мар 04 11:01, Andrei N. Sobchuck -> Dmitry Sidoroff:
DS>> Деструктор вызывается или GC или операцией удаления объекта.
AS> Тьфу ты. Hасчет того, что после вызова финализатора объект всегда еще
AS> живёт - я прогнал. Согласен.
AS> В моём же примере ниже, финализатор вызывается *после* фактического
AS> удаления объектов, для некоей группы объектов *скопом*.
AS> Ты создай мне деструктор с таким поведением. Это факт. И такое
AS> поведение существует до сих пор.
Очень кривое решение. Хотя бы потому что подразумевается что связь
"агрегирован в [группу]" единственная.
И со временем жизни шиза полная, обращение к уже несуществующим объектам.
AS> Деструктор же - артефакт "ручного" управления памятью.
AS> Вот смотри: http://quirks.chat.ru/cpp/faq/#s11p1
Полезу в инет посмотрю.
AS>>> Кстати, в том же VW ST (прямом наследнике ST-80) долгое время не
AS>>> было финализации основанной на отдельных объектах (как это
AS>>> например в Java). Вот так. Финализаторов нет, а зачистка
AS>>> ресурсов есть.
DS>> Зачем делать криво, если можно прямо?
AS> Это решение принималось в начале 80-х.
Тогда же и мой вариант был. Этот очень старый спор по сути сводится к "делать
правильно или проще". То и другое имеет свои преимущества.
Вот только не надо считать "проще" за "правильно".
AS>>>>> Кстати, что делать если дескриптор файла закрывается
AS>>>>> (финализатором) раньше, чем вызывается финализатор объекта?
DS>>>> Hичего не понял. Почему дескриптор файла стал отдельным
DS>>>> объектом?
AS>>> Ладно. Hе точно выразился. Hе дескриптор, а поток.
DS>> А в чем проблема? Тут-то мы знаем когда объект нужно уничитожить.
AS> Проблема в том, что у тебя в _деструкторе_ - вызывается операция
AS> записи в этот поток. Короче, ты заложился на поведение,
AS> обеспечиваемое деструктором и не обеспечиваемое финализатором.
Еще раз: проблемы попросту не существует.
Я, кстати, сторомозил, кэшер должен быть агрегирован в поток (иначе его нельзя
использовать в деструкторе). Что и гарантирует что поток жив и может быть
использован в деструкторе.
Либо можно это сделать через метакласс, который тоже гарантировано живой.
Dmitry
Естетсвенно к несуществующим объектам обращения нету.
Схема сложная (я бы сказал чере чур). Если она тебя интересует, то:
http://www.cincom.com/downloads/pdf/AppDevGuide.pdf
Но я приводил её только как иллюстрацию того,
что схема работы финализатора может быть довольно, гм, странной.
30 Мар 04 11:01, Andrei N. Sobchuck -> Dmitry Sidoroff:
AS> Деструктор же - артефакт "ручного" управления памятью.
AS> Вот смотри: http://quirks.chat.ru/cpp/faq/#s11p1
AS> Обрати внимание на вопросы 11.5, 11.6, 11.7, 11.8, 11.9, 11.11, 11.12.
AS> Слишком много особых условий, что бы ставить знак равенства.
AS> Это всё равно, что сказать, что ультрафиолет и видимый нами свет -
AS> одно и то ж, потому что всё это электро-магнитные волны. То есть с
AS> одной стороны это так, но есть и различия. Ты абстрагируешся не с той
AS> стороны :)
Прочитал. 5, 6, 7, 8, 9, 11, 12 - дестркутор явно вызывать нельзя и как с этим
боротся. Вполне очевидная вещь.
10 о ++ хаке для распределения памяти под объектры в ручную.
Принципиальные отличия от финализатора все равно осталось загадкой.
Dmitry
Принципиальная разница в том, что момент вызова финализатора не предсказуем
(вплоть до полного отсутсвия).
Вот еще увидел:
"What the heck is: Finalization"
http://www.sidhe.org/~dan/blog/archives/000388.html
...
Finalization is not the same thing as destruction,
though the two terms are often used interchangeably,
and in many systems they occur together. For the record,
while finalization is letting an object clean up after itself,
destruction is the system managing the object reclaiming
the resources it uses. If you want a concrete example,
consider the humble filehandle object. This is an object
that represents a file. Moreover, it automatically flushes the buffers
and closes the file when the filehandle is no longer referenced.
Not unusual behaviour for a filehandle.
(Well, at least not in perl. Other languages may vary)
*The finalization for that object is the closing of the underlying OS file.*
*The destruction of the object is the system deallocating*
*the memory for the buffers and putting the now-dead object*
*on the object free list for later reallocation.*
...
Обрати внимание на выделенные последние строчки.