这是一个荒谬的错误喜剧,我以前基本相反地理解了这些事情,并删除了我特定问题的所有引用。
我编写了一种定制的引用类型,不是真正的 Clojure 引用类型,但是一种类似的东西。一个带有内容受控变异的箱子。A 最终会变得稍像是原子或 ref。
我的类型是一种引用类型,有一个指向引用自身指向内容的可变字段,以及其他方便执行其他操作的 fields。我希望使用 compare and set 来修改这个可变字段。
在 "vanilla" Clojure 中编写,唯一能够实现这种方法的方法是使用原子或 AtomicReference 包装在 deftype 字段中的值。这工作,但增加了 1 或 2 个指针追逐级别。我想去掉这些额外的指针。
Java 提供了至少两种直接在可变字段上执行 compare and set 的设施(这些可能要求字段是 volatile 的,我忘记了)。这两种机制都通过创建一种类型的字段访问器对象来工作。类的一个典型模式似乎是,在静态初始化器中创建字段访问器对象,然后在执行 cas 类型的字段实例时使用它。
典型的模式不适合与原生的deftype一起使用,尽管你可以使一个deftype字段可变,但这也会使其成为私有,从而使得构建字段访问器对象变得困难。你不能从“外部”构建一个,因为字段是私有的,而且deftype也不提供进行静态初始化的方式。大致有几种解决办法,基本思路是在你的deftype中添加一个方法,这个方法除了创建和返回字段访问器对象外什么都不做,然后在某个顶层静态环境中构建一个deftype的伪实例并调用该方法。因此,这实际上是可行的,只是有点糟糕。
起初我尝试构建一个伪deftype实例,但最终我只编写了一个极简化版本的deftype,用来生成一个具有字段和一个静态初始化器的类,该初始化器为特定字段设置AtomicReferenceFieldUpdater。这也可行,但依赖于对asm库的一些经验,以及与aot编译兼容的细心处理(我认为这一点做到了,但不是很确定)。
Compare-and-set非常棒,如果能有一种方法在deftype字段上实现它而不需要在比较和设置的想要比较和设置的内容周围添加额外的对象封装,那就更好了。机制存在于Java/JVM中,但在Clojure中利用它非常痛苦。