Oberon space
General Category => Общий раздел => Тема начата: Губанов Сергей Юрьевич от Март 22, 2012, 09:35:41 am
-
Допустим я реализовал свою "строку". Это структура внутри которой лежит целое число -- как бы "умный указатель". Через это число некий ресурс (в данном случае память под буквы) может быть получен/использован/освобождён.
public struct UnmanagedString
{
private uint handle;
}
Работать с переменными типа UnmanagedString нужно по особой дисциплине: обычная инструкция копирования "=" для структуры UnmanagedString неприемлема. Для копирования нужно использовать не "=", а специальную процедуру.
Эта специальная процедура в данном случае либо выполнит копирование букв в другой участок памяти и вернёт другой handle, либо, что более оптимально, увеличит количество ссылок на существующую строку. В общем случае эта специальная процедура может сделать чёго-то более трудоёмкое.
Так вот. Возникает вопрос. Что надо минимально потребовать от языка программирования, чтобы программирование "умных указателей" не походило на организацию восхода Солнца вручную. Понятно, что в С++ это сделано далеко не минимально.
Можно было бы потребовать следующее: в языке добавить атрибут структуры означающий, что она некопируемая, а компилятору для таких структур проверять, что для переменных её типа нигде не использована инструкция "=" и они не переданы ни в какую процедуру по значению (только по ссылке). Соответственно, структуры и массивы содержащие некопируемые поля тоже должны быть маркированы атрибутом запрещающим копирование. Это можно было бы сделать, но можно сделать и наоборот...
В последней редакции Оберона-07 вообще никакие структуры не могут быть переданы в процедуру по значению, а только по ссылке. То есть Оберон-07 уже полшага к "умным указателям" сделал. Если действовать в духе Оберона, то лучше будет вообще запретить инструкцию копирования ":=" для любых составных типов. Это дёшево и сердито. Разрешаем применять ":=" только для базовых типов и всё. Копирование объектов составных типов пишем ручками через копирование полей (компилятор легко может это потом соптимизировать, если захочет, так что в рантайме оверхеда не будет).
Оптимум где-то по-середине. Некоторым составным типам копирование всё таки было бы полезно.
Короче, вопрос в следующем. Что разрешить для составных типов по умолчанию: копирование разрешено или запрещено? Если подумать, то очевидно по умолчанию копирование объектов составных типов должно быть запрещено, а разрешать применять к ним инструкцию ":=" программист должен явно (это в каком-то смысле всего лишь оптимизация).
-
Не есть гуд -ссылка это ссылка... иногда они создают дополнительный геморрои.. впрочем может ввести аналогично эйфелю - expanded (развернутые) типы?
-
А разьве expanded не тоже самое что и value? Засунули структуру внутрь объекта и всё.
Для строк это не годится - у них длина переменная.
-
Короче, вопрос в следующем. Что разрешить для составных типов по умолчанию: копирование разрешено или запрещено? Если подумать, то очевидно по умолчанию копирование объектов составных типов должно быть запрещено, а разрешать применять к ним инструкцию ":=" программист должен явно (это в каком-то смысле всего лишь оптимизация).
Запрет копирования структур - это такой страшный сон. Наказание за плохое написание циклов :)
На самом деле тебе нужен конструктор и константные мемберы. Это если подходить со стороны "минимизации". Константный мембер "защитит" от дефолтового копирования. Конструктор обеспечит правильную инициализацию этого мембера (через вызов специальной в твоем случае функции копирования). Да, конструктор подразумевает наличие семантики инициализации переменной (этого нет в обероне).
P.S. Хотя все равно не очень понятно как это будет нормально работать без деструкторов. Это неотъемлемая часть "умных указателей" и именно с деструкторами все непросто.
-
P.S. Хотя все равно не очень понятно как это будет нормально работать без деструкторов. Это неотъемлемая часть "умных указателей" и именно с деструкторами все непросто.
Вот именно. И именно запретом по умолчанию оператора ":=" (в добавок к тому что и так есть в последней редакции Оберона 07) мне видится можно убить большое количество зайцев. Если нет неконтролируемого копирования, значит нет неконтролируемых копий, значит надобность в неявном вызове деструкторов отпадает. А в тех местах где явно/врукопашную скопировал, там же явно/врукопашную и вызвал для этой копии деструктор.
Можно сделать немного по-другому. Например, так: в родном модуле, в котором структура объявлена, для неё оператор ":=" разрешён, а в остальных модулях по умолчанию запрещён.
-
Можно сделать немного по-другому. Например, так: в родном модуле, в котором структура объявлена, для неё оператор ":=" разрешён, а в остальных модулях по умолчанию запрещён.
Запрет на копирование мне кажется чересчур жестоким, без смайликов. При этом особого профита все равно не видно - компилятор ничего не контролирует, все делаем ручками.
Мне кажется, что от идеи деструкторов в традиционном ЯП все равно никуда не уйти и она должна быть представлена хоть в каком-то виде. Не надо делать кальку с C++. Пойти непосредственно от идеи: контролируемая (автоматически) инициализация/деинициализация. Контролируемая не только в скопе, но и явная передача контроля вверх/вниз по стеку - это покроет 90% случаев, когда хочется полуавтоматического контроля за ресурсами. И для реализации этой идеи не надо всех тех наворотов, которые есть в С++ (конструкторы копирования, операторы присваивания и т.д.).
-
Пойти непосредственно от идеи: контролируемая (автоматически) инициализация/деинициализация. Контролируемая не только в скопе, но и явная передача контроля вверх/вниз по стеку - это покроет 90% случаев, когда хочется полуавтоматического контроля за ресурсами.
Я не понял о чём ты.
-
Я не понял о чём ты.
Забей :) Когда будет у меня нормальный пропозал - напишу сюда.
-
Я тут ковыряю Go (может в принципе по работе пригодиться), возможно вот это будет тут в тему: http://golang.org/doc/go_spec.html#Defer_statements
-
Я тут ковыряю Go (может в принципе по работе пригодиться), возможно вот это будет тут в тему: http://golang.org/doc/go_spec.html#Defer_statements
Ну да, это один из возможных "минимальных" подходов. Очень минимальных. Как я понял - он не реюзается. И его нельзя мувать вверх/вниз по стэку.
-
Я тут ковыряю Go (может в принципе по работе пригодиться), возможно вот это будет тут в тему: http://golang.org/doc/go_spec.html#Defer_statements
Ну да, это один из возможных "минимальных" подходов. Очень минимальных. Как я понял - он не реюзается. И его нельзя мувать вверх/вниз по стэку.
Вроде бы да, нельзя. А зачем тебе перетасовывать стек?
PS. Если бы подобное было бы в симбиане… Быть может он и не сдох бы. Ибо это сняло бы процентов 60 того BDSM'a c которым приходилось иметь дело разработчику.
-
Вроде бы да, нельзя. А зачем тебе перетасовывать стек?
В смысле я хочу вернуть такую штуку из функции. Или передать в функцию. И чтоб оно сделало свою работу (финализирующую) автоматически, гарантировано, и без отвлекания внимания.
-
Вроде бы да, нельзя. А зачем тебе перетасовывать стек?
В смысле я хочу вернуть такую штуку из функции. Или передать в функцию. И чтоб оно сделало свою работу (финализирующую) автоматически, гарантировано, и без отвлекания внимания.
ну, это ж statement а не expression. shared_ptr через это не сделать. а вот scoped_ptr - легко.
-
Я тут ковыряю Go (может в принципе по работе пригодиться), возможно вот это будет тут в тему: http://golang.org/doc/go_spec.html#Defer_statements
Это синтаксический сахар. Он ничего не добавляет по сути.
У меня задача вот какая. Те UnmanagedString о которых я говорил создаются в одном потоке как поля объекта-сообщения, далее этот объект-сообщение обрабатывается в другом потоке и удаляется (фактически помещается в пул для повторного использования). Во время уничтожения все его поля чистятся, соответственно у UnmanagedString вызываются деструктор и она отправляется в свой пул для повторного использования. Так вот мне хочется от языка и от компилятора гарантии, чтобы нигде эта строка никуда не была скопирована простым оператором ":=". Время её жизни равно времени жизни объекта-сообщения и если кто-то её скопирует себе простым оператором ":=", то потом получит сюрприз. Вот поэтому я и думаю о запрете оператора ":=" для некопируемых структур.
-
Вот поэтому я и думаю о запрете оператора ":=" для некопируемых структур.
Я так понимаю, что спрятать структуру за указатель нельзя, потому что мы боремся с GC?
-
Я тут ковыряю Go (может в принципе по работе пригодиться), возможно вот это будет тут в тему: http://golang.org/doc/go_spec.html#Defer_statements
Это синтаксический сахар. Он ничего не добавляет по сути.
Это действительно не то что тебе нужно, но это и не синтаксический сахар.
У меня задача вот какая. Те UnmanagedString о которых я говорил создаются в одном потоке как поля объекта-сообщения, далее этот объект-сообщение обрабатывается в другом потоке и удаляется (фактически помещается в пул для повторного использования). Во время уничтожения все его поля чистятся, соответственно у UnmanagedString вызываются деструктор и она отправляется в свой пул для повторного использования. Так вот мне хочется от языка и от компилятора гарантии, чтобы нигде эта строка никуда не была скопирована простым оператором ":=". Время её жизни равно времени жизни объекта-сообщения и если кто-то её скопирует себе простым оператором ":=", то потом получит сюрприз. Вот поэтому я и думаю о запрете оператора ":=" для некопируемых структур.
А! Хочется "гермитичности типов"? :-) То есть гарантировать чтобы ни один гад не сохранил "указатель" на сущность которая потом будет "удалена". В общем то умный указатель (типа shared_ptr) тут тебе не поможет, в том плане, что он предотвратит не утекание указателей в левые места, а удаление сущности в случае если они таки утекли. Гарантию в рантайме тут даст только какой-нибудь weak_ptr. Но гарантия в рантайме - это слишком слабая гарантия (IMHO).
Таким образом, умные указатели (как и сборщики мусора) тут совершенно не в тему.
По сути тебе тут для твоих "ссылок" (UnmanagedString) нужно изобрести механизм аналогичный обероновско-виртовской передачи по ссылке записей на стеке (VAR-параметры) и невозможности взять их адрес (получить указатель/ссылку на них в явном виде, которую можно скопировать и так далее).
PS. А в шарпе не бывает opaque типов?
-
Я так понимаю, что спрятать структуру за указатель нельзя, потому что мы боремся с GC?
Ага. Я написал struct UnmanagedString { private uint handle; } именно для того чтобы не использовать стандартную указательную System.String.
А! Хочется "гермитичности типов"? :-) То есть гарантировать чтобы ни один гад не сохранил "указатель" на сущность которая потом будет "удалена".
Ага. В общем то умный указатель (типа shared_ptr) тут тебе не поможет, в том плане, что он предотвратит не утекание указателей в левые места, а удаление сущности в случае если они таки утекли.
Меня такой вариант устроит на 100% если "утекание" будет явным (легко найти поиском). По сути тебе тут для твоих "ссылок" (UnmanagedString) нужно изобрести механизм аналогичный обероновско-виртовской передачи по ссылке записей на стеке (VAR-параметры) и невозможности взять их адрес (получить указатель/ссылку на них в явном виде, которую можно скопировать и так далее).
Да-да-да. Именно об этом я тут и говорю. О невозможности передать UnmanagedString в процедуру не иначе как по ссылке (в Обероне VAR, в C# ref), и о запрете использования для переменных оператора присваивания "=". PS. А в шарпе не бывает opaque типов?
System.Object, abstract class, interface сойдут?
-
По сути тебе тут для твоих "ссылок" (UnmanagedString) нужно изобрести механизм аналогичный обероновско-виртовской передачи по ссылке записей на стеке (VAR-параметры) и невозможности взять их адрес (получить указатель/ссылку на них в явном виде, которую можно скопировать и так далее).
Да-да-да. Именно об этом я тут и говорю. О невозможности передать UnmanagedString в процедуру не иначе как по ссылке (в Обероне VAR, в C# ref), и о запрете использования для переменных оператора присваивания "=".
Ну, если б у меня такая задача возникла бы в джаве, я бы посмотрел в сторону аннотаций (создание своего типа аннотаций) и своей тулзы для их анализа на этапе компиляции (это в джаве делается просто). Насколько я помню, в шарпах всяких есть какой-то аналог этих самых аннотаций. Соответственно тулзень выдавала бы на этапе компиляции ошибку если б какой-то гад попробовал бы утащить куда-то не туда мою преелесть структуру-псевдоссылку.
-
А в Яве уже есть структуры (value-type)?
-
А в Яве уже есть структуры (value-type)?
Нет. Но рантайм и без них неплохо справляется. На стеке когда нужно размещает. В непрерывный кусок памяти сгребает пачку "структур" (в случае того же массива) и так далее.
Я говорил про то, что если б я не хотел чтобы некая ссылка не уплыла куда не надо, или чтобы запретить в некоторых случаях вызовы некоторых методов у некоторых объектов на этапе компиляции, и мне не хватало бы для этого механизмов инкапсуляции жабы (всякие там public/protected/private/default), я бы использовал аннотации.
-
Пока этот форум был в оффлайне пообсуждали данный вопрос на RSDN:
Приватный operator=
http://rsdn.ru/forum/dotnet/4685453.1.aspx
-
Пока этот форум был в оффлайне пообсуждали данный вопрос на RSDN:
Приватный operator=
http://rsdn.ru/forum/dotnet/4685453.1.aspx
А ты не смотрел в сторону WeakReferences? (http://msdn.microsoft.com/en-us/library/ms404247.aspx)
По идее при сборке мусора мусорщик не должен на них оглядываться, то есть алгоритм выяснения кто жив а кто нет должен работать независимо от числа слабых ссылок.
-
Ничего полезного в слабых указателях для меня нет.
-
Ничего полезного в слабых указателях для меня нет.
То есть GC при проверке на живущесть объекта все же пробегается и по всем слабым ссылкам? Если да, это это явный косяк реализации.
-
То есть GC при проверке на живущесть объекта все же пробегается и по всем слабым ссылкам?
Зачем бы ему это делать?
Я говорю что мне они даром не нужны. Применить их не к чему.
-
По-моему, наличие слабой ссылки не отменяет указатель. Вроде бы, если указателю на объект присвоить новое значение, то старый объект считается мусором: слабые ссылки-то не обходятся... А значит, в один прекрасный момент мусор будет собран, и слабые указатели как минимум перестанут указывать на объект.
-
По-моему, наличие слабой ссылки не отменяет указатель. Вроде бы, если указателю на объект присвоить новое значение, то старый объект считается мусором: слабые ссылки-то не обходятся... А значит, в один прекрасный момент мусор будет собран, и слабые указатели как минимум перестанут указывать на объект.
Именно в этом и их смысл - если сильных ссылок не осталось, объект стал мусорным и слабые ссылки становятся не валидными. (в некоторых релизациях они обнуляются)