这是一个好笑的错误喜剧,我之前基本误解了相反的情况,并删除了所有关于我的特定问题引用。
我编写了一种定制的引用类型,不是真正的Clojure引用类型,但类似的事物。一个对盒子内容的控制变异进行包装的盒子。A最终会有一些类似atom或ref的样子。
我的类型是引用类型,有一个可变字段,它指向引用本身指向的内容,还有其他字段以方便其他操作。我想使用比较和设置来变异这个可变字段。
在"vanilla" Clojure中编写,唯一的方式来此是通过在deftype字段持有值周围使用atom或AtomicReference包装器。这可以工作,但增加了1或2个指针追踪级别。我想去掉那些额外的指针。
Java提供了至少两种直接在可变字段上执行比较和设置的设施(它们可能需要字段是volatile的,我忘记了)。这两种机制都通过创建一种字段访问器对象来实现。类的一个典型模式似乎是创建字段访问器对象在静态初始化器中,然后在执行cas类型操作时,根据实例的字段使用它。
标准的模式与当前的deftype不兼容,因为虽然你可以将deftype字段设置为可变的,但这也会使其成为私有的,从而使得构建字段访问器对象变得困难。由于字段是私有的,因此你无法从外部构建它,并且deftype没有提供进行静态初始化的方法。解决这个问题有几种方法,基本上是给deftype添加一个方法,这个方法除了创建和返回字段访问器对象外,什么都不做。然后在某些顶级静态环境中构建一个dummy类的实例并调用该方法。因此,这种方法是可行的,但令人相当头疼。
起初我尝试创建dummy的deftype实例,但最终只是编写了一个极为简化的deftype版本,通过生成一个类,该类具有字段和一个静态初始化器,用于设置特定字段的AtomicReferenceFieldUpdater。这也可行,但这需要一些使用asm库的经验,并且需要注意使其与AOT编译(我想我已经做对了,但并不确定)良好兼容。
比较和设置是一个很棒的功能,如果能提供一个在不围绕我们要比较和设置的内容添加额外对象包装的情况下在deftype字段上执行它的方式就更好了。在Java/JVM中存在实现这一功能的方法,但在Clojure中利用它们相当痛苦。