Не совпадает тип? Похер, притянем за уши. Лишний бит в указателе? Похер, замаскируем. Это указатель на структуру? Да похер же, замаскируем и возьмём поле (потому что операции с полями структур это на самом деле всё та же самая адресная арифметика).
Нужно сделать.. вот так?
(void**)&(((cons_t*)_PTR(ptr))->car) = ref_new_obj();
да, тащемта, лехко! Если вам нужно выстрелить себе в ногу своими же собственными яйцами (даже если у вас их нет), причём в качестве ружья вы очень хотите использовать подсвечник, который якобы у вас вместо левой руки - нет инструмента лучше Си. Волшебная палочка Гарри Поттерсона - это такая хуйня...
Итог:
(SETF C (LIST 1 2 3)) ; создаём символ, в который запихиваем список (его тоже создаём)
(SETF (CAR C) "Zulu") ; берём голову списка C и заменяем её на зулуса
(PRINT-CONTEXT) ; а это так, отладка.
-----
C: ( "Zulu" 2 3 )
Утечек памяти нет. Но чтобы это работало... пришлось поизврщащааЦО. Мозг кипит. Идея с тэгированными указателями необычайно продуктивной оказалась.
Второй итог: из-за изменившейся идеологии доступа к данным (надеюсь, больше не потребуется её пересматривать!) надо перелопатить код всех уже реализованных операторов и bltin-функций. Не смертельно, но это уже третий раз... :)))
P.S. и у меня возник страшный воперос: сколько памяти на самом деле берёт malloc(), если мы выделяем, например.. ну, скажем, один байт? Я так понимаю, внутренняя механика там жёстко завязана на alignment машины и на 64-битном компе потратится не 1 байт, а гораздо больше При этом я не считаю "затратами" возвращаемое значение указателя - оно неизбежно... интереснее то, что там в памяти за мухлёж. Наверное, где-то ПЕРЕД выделенной памятью записывается структура, в которой указан.. ну, хотя бы размер выделенного блока, штоли. Чтобы free() знал, сколько можно обратно в мусор отправить. Но ведь ещё должны быть где-то какие-то структуры, списки, таблицы или х.з. что, где хранится общая картина - сколько выделено, где выделено, сколько памяти ещё можно отгрызть и засрать. Ведь сам malloc() как-то же находит НОВУЮ память, так где он, шьёрт побери, всё это хранит?
Интерес чисто академический, конечно, ибо повлиять на этот механизм я не могу.. разве что написать свой malloc, с монашками и лаптой, чтобы сэкономить хотя бы на выделении cons-ячеек (ибо их дохера и все они одинаковые - всего-то два указателя).
Теперь такие вот конструкции:
(SETF (CAR (CDR (CDR (CDR (CDR B) ) ) ) ) (CONS :KEY "SUPRPIZE!") )
работают именно так, как предполагается - память в ячейке высвобождается, туда заносится новое значение и обновлённый список сверкает своими полями. Но вот только для того, чтобы эта примитивная (для Лиспа!) механика заработала бы как подразумевается, пришлось наворотить горы сишного кода. Зато - да, пофиг на тип, пофиг на адрес, пофиг на всё - система разрюхает, что от неё хотят и либо сделает, либо скажет, что это невозможно. И это открывает возможность реализовать если не весь функционал CL, но многое и многое.
Надо ещё подумать над исключениями - бэктрейс и прочий матан большого лиспа реализовать не хочу от слова "НЕЕЕЕЕЕТ!!!!!!", а вот пробросить изнутри поскользнувшейся функции сообщение на верхний уровень - это было бы полезно.