Регистрация | Войти
Lisp — программируемый язык программирования
RSS
улучшение системы типов для SBCL
den73 - 14.11.2017 22:36, Сообщений - 5
Точнее, исправление багов. 
(defparameter *g* (cons 1 2))
(defun g () (setf (car *g*) 'a))

(defun f (x)
  (when (typep x '(cons fixnum))
    (g)
    (if (typep x '(cons fixnum))
      "Still cons fixnum!"
      "Not cons fixnum"
)
)
)

(f *g*)
Эту багу исправил. Штатные тесты проходят кроме одного, SBCL этим SBCL-ем собирается, моя игрушка тоже. Т.е. не совсем помойка. 
Подробности - тут: https://www.linux.org.ru/forum/development/13789998

Теперь хочу сделать Object.Freeze из Javascript. В связи с этим вопрос к знатокам: есть ли в 64-разядном SBCL в консе свободное место, где можно разместить флаг замороженности? Тот же вопрос про массивы и структуры. 

[#]
Это обнадёживает!) Вот бы руки дошли хорошенько это рассмотреть)
Вопрос про размещение дополнительного флага пробовал основным разработчикам задавать? Что говорят?
LinkFly - 15.11.2017 23:14
[#] Ответ на комментарий от LinkFly 15.11.2017 23:14
Общение с основными разработчиками травмирует мою тонкую психику. 

Но я уже сам разобрался: конс - это ровно два объекта, без всяких заголовков, и свободного места в самом консе нет. 

http://www.chiark.greenend.org.uk/doc/sbcl-doc/html/sbcl-internals/Heap-Object-Layout.html

Дальше можно решать по-разному:

а) добавить к каждому объекту ещё целое слово, чтобы поместить в это слово него флаги. 

Решения могут быть такие:
а) использовать тот факт, что 64-разрядные системы на самом деле имеют разрядность намного меньше (https://www.linux.org.ru/forum/development/5647234?filter=show). Соответственно, реально указатель на лисповый объект вроде как должен начинаться с энного количества нулей, которые можно занять как раз флагами. Проблема: я не знаю, имеет ли место такой факт :) И плюс к тому, я могу оказаться не первым таким умным. Например, сборщик мусора может класть в это место свои заметки. 

б) выделить отдельный статический массив, который хранит признаки иммутабельности, и двигать данные в нём во время сборки мусора. Не говоря о снижении производительности, выглядит приемлемым вариантом. 

в) самое тупое: хранить признак иммутабельности в eq хеш-таблице, ключём является сам объект. Я пока так и сделал, поскольку организовать хранение - это полдела. Нужно ещё поменять систему типов, чтобы в ней можно было выразить иммутабельность и чтобы она могла о ней рассуждать при выводе типов. 




den73 - 16.11.2017 17:36
[#] Ответ на комментарий от den73 16.11.2017 17:36
Блин, коряво я написал. Итого 4 варианта действий :) 
den73 - 16.11.2017 17:37
[#] Ответ на комментарий от den73 16.11.2017 17:37
Залил  реализацию проверки для вектора. Пока работает только динамически и на базе хеш-таблицы. Теперь хочу попытаться научить систему типов это понимать, хотя не думаю, что это будет легко. 

Даже если не выйдет - теперь я знаю, что можно переопределить (define-source-transform data-vector-set) и отлавливать запись в векторы. Правда, нет уверенности, что _любую_ запись можно отловить, даже если пересобрать SBCL с таким модифицированным определением, но вроде бы так должно было быть. 


den73 - 16.11.2017 18:08
[#] Ответ на комментарий от den73 16.11.2017 18:08
Вроде реализовал иммутабельность для хеш-таблиц. Цитата из тестов:

(defparameter *hash-table-to-freeze* (make-hash-table))

(with-test (:name :table-is-freezed-and-its-type-is-changed)
   (assert (typep *hash-table-to-freeze* '(and hash-table (mutable 1))))
   (freeze-object *hash-table-to-freeze*)
   (assert (typep *hash-table-to-freeze* '(and hash-table (mutable 0))))
)


(with-test (:name :writing-to-mutable-and-immutable-hash-table)
   (defun mutate-the-mutable-hash-table (x)
     (setf (gethash 33 (the (and hash-table (mutable 1)) x)) 55)
)

   (compile 'mutate-the-mutable-hash-table)
   (assert (= 55 (mutate-the-mutable-hash-table (make-hash-table))))

   ;; this should err
  (assert-error (mutate-the-mutable-hash-table *hash-table-to-freeze*))
)


(with-test (:name :compiler-warns-on-writing-to-hash-table-declared-as-immutable)
   (macrolet ((compilation-failure-p (definition)
                `(multiple-value-bind (function warnings-p failure-p)
                                      (let ((*evaluator-mode* :interpret))
                                        (eval '(compile ,definition))
)

                   failure-p
)
)
)


     (assert (compilation-failure-p
              (defun mutate-the-hash-table-declared-immutable (x)
                (declare (type (and hash-table (mutable 0)) x))
                (setf (gethash 4 x) 5)
)
)
)


     (assert (compilation-failure-p
              (defun mutate-the-hash-table-declared-mutable (x)
                (declare (type (mutable 0) x))
                (setf (gethash 4 x) 5)
)
)
)
)
)


Если попросту, то декларация типа или (the (mutable 1) x) говорит о том, что данный объект - мутабельный (но реализовано это только для хеш-таблиц). 
Соответственно (the (mutable 0) x) говорит о том, что x - иммутабельный. Хеш-таблица всегда рождается мутабельной, но может быть заморожена вызовом freeze-object, после чего становится иммутабельной. Компиляция кода, пишущего в объект, декларированный иммутабельным, приводит к предупреждению компиляции. Попытка выполнить такой код приводит к ошибке времени выполнения. Попытка записи в замороженный объект является ошибкой (соответствующая проверка стоит в и рантайме). 

Есть некие намётки, чтобы поддерживать иммутабельность структур. Во-первых, структура иммутабельна, если все её поля - read-only. Но этого недостаточно. Нужно ещё уметь замораживать структуру. Пока не умею это сделать, и не факт, что успею за оставшееся отведённое время. 

Ещё хочется, но пока страшно попробовать интегрировать иммутабельность в систему вывода типов. В SBCL есть два механизма вывода типов - собственно вывод типов и "constraint propagation", который задаёт локальные ограничения, например, для веток А и Б в (if (typep x 'foo) А Б). Я не знаю, понимают ли эти механизмы время. Т.е. можно ли им объяснить, что если объект сейчас немутабельный, то в будущем он останется немутабельным, а в прошлом может быть и мутабельным. Так что пока я вообще исключил мутабельность из вывода типов - она будет работать только с declare type и с явным the. 

Что немаловажно, можно декларировать (and (mutable 0) hash-table) и вроде это нормально обрабатывается. 


den73 - 28.11.2017 21:41
@2009-2013 lisper.ru