Подтвердить что ты не робот

Переменные поля в Clojure deftype?

Я тестирую Clojure 1.2, в частности изменяемые поля, которые поддерживаются в deftype в соответствии с clojure.org documentation.

Но я не могу заставить набор работать. Каков синтаксис для обновления поля? Или еще не реализована изменчивость?

(definterface IPoint
  (getX [])
  (setX [v]))

(deftype Point [x]
  IPoint
  (getX [this] x)
  (setX [this v] (set! (.x this) v)))

user=> (def p (Point. 10))
user=> (.getX p)
10
user=> (.setX p 20)
ClassCastException: user.Point cannot be cast to compile__stub.user.Point

Использование моментального снимка 1.2 с нескольких дней назад.

4b9b3361

Ответ 1

deftype default по-прежнему должен иметь неизменяемые поля; чтобы переопределить это, вам необходимо аннотировать имена полей, которые должны быть изменены с помощью соответствующих метаданных. Кроме того, синтаксис для set! полей экземпляра отличается. Пример реализации, чтобы сделать работу выше:

(deftype Point [^{:volatile-mutable true} x]
  IPoint
  (getX [_] x)
  (setX [this v] (set! x v)))

Там также :unsynchronized-mutable. Разница заключается в том, что имена будут предлагаться опытному разработчику Java.;-) Обратите внимание, что предоставление либо аннотации имеет дополнительный эффект, чтобы сделать поле частным, так что прямой доступ к полю становится невозможным:

(.getX (Point. 10)) ; still works
(.x (Point. 10))    ; with annotations -- IllegalArgumentException, works without

Кроме того, 1.2, скорее всего, поддержит синтаксис ^:volatile-mutable x как сокращенное обозначение ^{:volatile-mutable true} x (это уже доступно в некоторых новых ветвях с числами).

Оба варианта указаны в (doc deftype); соответствующая часть следует - помните об этом!

Поля могут быть квалифицированы   с метаданными: volatile-mutable true или: unsynchronized-mutable   true, в какой момент (set! aal aval) будет поддерживаться методом   тела. Хорошо заметьте, что изменяемые поля чрезвычайно сложны в использовании   правильно, и присутствуют только для содействия созданию более высоких   как, например, Clojure ссылочные типы, в Clojure  сам. Они предназначены только для экспертов - если семантика и   последствия: volatile-mutable или: unsynchronized-mutable не являются   вам сразу же не следует использовать их.

Ответ 2

Как и большинство вещей в Clojure, поля в типах, определенных с помощью deftype являются неизменяемыми. Хотя вы можете обойти это, используя :volatile-mutable/:unsynchronized-mutable аннотации, это вообще не распространено. С одной стороны, такие аннотации сделают поле закрытым, поэтому только методы, определенные для типа, смогут получить к нему доступ (и, следовательно, установить его). Но что еще более важно, такие конструкции восприимчивы к гонкам данных.

Когда требуется изменчивость, idomatic Clojure будет использовать один из ссылочных типов Clojure, такой как atom или ref.