• ada Delphi Взял для разнообразия новый проект. Вот никогда не фанател от упрощённого стиля Windows 10. В Мак ОС Десять до сих пор кажется эстетичной Аква, а безальтернативная упрощёнка — это что-то мимо. Но, поди ж ты, оказывается, это востребовано. Хотят в этом стиле. А ещё хотят, чтоб в этом стиле и на Семёрке работало. Всё указывает на выбор Делфи как инструмента реализации. Они там давно (кажется, в XE2) встроили стилизацию и научились мимикрировать под элементы управления, обычно наблюдаемые только в Метро. Решающий вклад тут вносит, что со времён Делфи 2006 возобновлена раздача базовой версии на шару. Без этого приходилось постоянно иметь дело с натленной Делфи Семь, как у легальных пользователей, так и у пиратов, и нового софта не появлялось, соответственно, интересных заказов — тоже.

    По этому поводу получил возможность забуриться в свежий Делфи Токио. И сравнить с Адой. Первым делом зашёл в настройки проекта посмотреть, как там дела по умолчанию со включениям проверок времени выполнения. Негусто. Всё выключено. Никак видеокодеки опять пишем или на Розеттакоде секундами меряемся. Часы моего времени на отладку дороже, поэтому всё врубил. Во всяком случае, всё, что смог, а было там только три галочки. Но совсем как в Аде писать всё равно не получилось. Не хватило ещё проверки указателя на null-nil до того, как пытаться по нему пройти. На Аде я могу забуриться внутрь сложного JSON значения, а если где-то что-то не нашлось, вылететь по известному исключению в обработчик, который ничего не сделает. В Делфи, по крайней мере, в стандартной библиотеке, если не брать мои CVariants, такая история не работает. Ну или лучше не пользоваться. «X.Values['ObjectKey'] as TJSONString» запросто может оказаться nil, и если дальше у него получить Value, то вылетает исключение Access Violation с доступом к первым байтам виртуальной памяти. Чё-т как-то не очень такое ловить. Лучше б что-то языковое бросалось ДО попытки вызвать метод через такой указатель.

    Освежил воспоминания, почему @akastargazer так радовался, что в Обероне не надо так париться управлением памятью. Как адаисту со стажем, мне это было не очень понятно, что там париться, и зачем решать эти проблемы таким изуверским способом, а тут вот оно всплыло. За каждый TJSONObject и TJSONPair трясёшься, чтоб он только не утёк, если на полпути исключение вылетит. Всё огораживаешь в try-finally-FreeAndNil-end, всем значениям, которые могли бы при прочих равных быть промежуточными, даёшь имя переменной. В GNATCOLL.JSON такого страха не было, и в моих делфёвых CVariants такого страха нет. Там RAII и счётчик ссылок внутри. Но столбовой дорогой это до сих пор не стало.

Replies (9)

  • @OCTAGRAM, Эм...
    В первом случае обертка с проверкой на null и выбросом исключения через raise ... at ...?
    Во втором сделать отдельный список созданных объектов с очисткой в одном месте (в деструкторе парсера, например, или когда там тебе надо)?
  • @Zawullon, 1. Этак для каждого класса понадобится обёртки делать.
    2. Нет, там сложнее. Вот получил я, допустим, ответ от Фейсбука в Джейсоне, разпарсил, и из словаря извлёк только data. Этот data во всей его полноте я бы хотел поместить прямо в конфиг, только ещё пару полей добавить надо, которых там нет, маркер доступа хотя бы.
    Итак, есть корневой объект — продукт парсера. Он уже не нужен, но если его убить, он потащит за собой data, а data трогать не надо, зато надо бы грохнуть TJSONPair, который описывает эту data. Какого-то владельца, как у компонент, я не наблюдаю. Есть IsOwned, но я не вполне понимаю, что это. Это я типа должен поставить DataObject.IsOwned := False , удалить из FacebookResponseObject, затем добавить в ConfigObject и поставить обратно IsOwned := True, так? Или не так? Или так, но в другом порядке?
    Со счётчиком ссылок просто выражаешь свои мысли, и оно работает, временно имея счётчики ссылок больше единицы, то тут думаешь, как бы сделать, чтоб не утекло, и это парит больше, чем следует.
  • @OCTAGRAM, 1 — эм, если такие проблемы для кучи классов, то это скорее ошибка в общем подходе к разработке. Бывает, когда на другой язык переключаешься, а патерны от первого в голове остались.
    2 — предполагаю, что IsOwned для удаления вместе с родительским обьектом. Возможно твой вариант с переключением прокатит, надо исходник смотреть, но это как-то... неправильным кажется... Т.е. у тебя есть reader и есть writer. Это, грубо говоря, разные сущности. Для каста одного в другой надо этот каст целиком писать. Тот факт, что внутри этих сущностей элементы описываются одинаковыми классами — это просто частный случай. Да, это позволяет перекинуть элементы из одного в другой по ссылке, но это хак для скорости/памяти. И его стоит воспринимать именно как хак для оптимизации, а не как штатное решение. Со всеми вытекающими костылями.
    Это все imho, если что)))
  • @Zawullon, 1. В Делфи это всё реализуемо. Ведь сейчас и так исключение вылетает, Access violation по факту обращения. А пусть лучше будет нормальное языковое.
    2. Нормальное отношение к значению как к значению. TJSONValue — буквально JSON-значение.
  • @OCTAGRAM, 1 — ну сделай себе вместо as функцию CastTo и юзай ее. as сам по себе подразумевает или проверку на nil сразу после вызова. Отсутствие проверки — это классическая ошибка разыменовывания нулевого указателя. Она есть и в сях, и в плюсцах, и тут.
    2 — объект — это ссылка. Не надо его воспринимать, как значение.
  • @Zawullon, 1. В языке Ада есть access и access constant, второе — указатель на константу, а в Делфях нету. В языке Ада точно так же есть not null access — указатель, который не может быть null. not null access можно передавать туда-сюда, и проверки дополнительные не требуются. Они требуются только при приведении access к not null access. И точно так же в Делфях такого нету. То есть, в языке эта фича вполне может быть, но конкретно в Делфи не добавили, хотя уж для методов могли бы.
    2. Возвращаемся к страху и геморрою, являющимися (пока) столбовой дорогой. Вообще, у них в мобильных компиляторах, а теперь ещё и в Линуксе ARC есть, но в самые интересные компиляторы, для Виндоуз и Мак ОС Десять, почему-то так и не дошло. Какие-то проблемы совместимости у них там лезут. Очень странно это читать. Берём объявляем во всём старом коде ссылки на объекты слабыми небезопасными, а сильная одиночная ссылка, дающая единичку в счётчике ссылок, получается, что явно нигде не присутствует. Какая-то из слабых небезопасных на самом деле играет роль сильной, но в старом коде это неясно. И если дёргать AcquireException или AddRef, то это тоже увеличивает счётчик ссылок, но в явном виде сильные ссылки не появляются. А в новом коде — как принято в ARC, сильные ссылки по умолчанию. И всё получается совместимо. Но они ж ведь так не хотят. У них либо вообще нет ARC (кроме интерфейсов COM), либо есть, но ссылки везде по умолчанию сильные, не совместимо со старым кодом, а если так с наскоку не получается, то и «не доставайся же ты никому». Это при том, что индексацию строк уже начинают делать с нуля, и для управления этим поведением есть директивы компилятора. Вот строки с нуля или единицы с поддержкой старого кода они могут сделать, а ARC с поддержкой старого кода — не могут. Вот не могут, и всё тут, ну что ты будешь делать.

    На странице пожеланий для Делфи вот уже сколько лет висит в топ 10 Report #21729 Record Operator Overloading: Please implement "Initialize" and "Finalize" operators. Отправили его в 2005м, я там отписывался в 2006м. RTL была готова к этому как минимум в Delphi 7, раньше я просто не ковырял, а есть подозрение, что и с Delphi 4, когда интерфейсы только появились. Там для типов, требующих инициализации, финализации и/или особого подхода при копировании, есть специальный RTTI, описывающий структуру, чтоб любую городушку из динамического массива из записей, содержащих строки, интерфейсы, замыкания или вложенные динамические массивы, можно было прибить или скопировать. И в эту структуру нужно только ещё один тег добавить для навешивания пользовательских функций Initialize/Adjust/Finalize и научить компилятор этот тег вставлять, и всё, уже бы давно сделали. RTL я патчил, благо, она в открытых кодах. RTTI, к сожалению, тоже надо патчить, а это уже сложнее, это либо во время выполнения снимать защиту от записи со страницы памяти, рискуя нарваться на DEP, либо exe патчить, но для разработчиков компилятора это по-любому должно быть просто. Там давно всё готово. Нет же! Не сделали!

    RAII для JSON подходит больше, потому что там можно всякие толстые указатели сделать с глубоким COW, и тогда значение будет действительно значением, но при этом внутри, конечно, всё разруливается ссылками. Лечить недостаток RAII при помощи ARC — это как-то не очень правильно, но всё идёт к тому, что в Делфях человеческого решения проблемы мы не дождёмся, хоть там сколько лет ещё пожелание в топ 10 будет висеть. И даже менее человеческого ARC всё никак не можем увидеть.
  • @OCTAGRAM, Ну так хотелки, это хотелки и есть. Я тоже много чего хочу, но писать свой компилятор не готов))) Хотелки — это отдельная тема)
  • @Zawullon, Хотелки — это предположение. А на примере языка Ада можно делать предметные сравнения. Лучше успевать фиксировать, пока глаз не замылился. Для того и написал.

    Ещё я считаю, что Ада — прогресс, но не единственный возможный путь прогресса, но тогда другие возможные ветви должны наследоваться (в том числе) от Ады, аргументируя изменения в языке, а не как Циклон и Раст, занимать «незанятую» нишу, «забывая» проделать сравнение с другими подходами (как требуют в любой нормальной научной работе), в том числе с Адой, и перекладывая задачу сравнения руководств по языкам на других людей, а по факту из-за такой «забывчивости» по отношению к Аде, и вовсе не сильно двигаться в прогресс, так и оставляя хорошие фичи только в Делфи и Аде. Бывает, напишут, что якобы безопасный язык программирования, копнёшь какую-нибудь Джаву, а там, батюшки, инты переполняются без исключений. И что их, так каждую однодневку Циклон проверять?

    Вот ещё и для прогресса надо фиксировать, что в языке Ада получилось хорошо, чтоб заимствовали активнее.
  • @OCTAGRAM, Если с этой стороны взглянуть, то да.