卑微的分解

2022-02-21 15:31:13

现在感觉是一个很好的时机,让这个博客成为一个真正的日志,记录我在开发Clojure UI库(Humble UI)时的发现。

这些决定都不是最终决定,可能随时会改变。事实上,我的期望是,在公共场合谈论它们可能会有助于巩固或取代它们,就像橡皮鸭一样。

Humble UI是一个Clojure框架,但它基于Java库JWM和Skija。Skija绘制图形,JWM负责窗口管理和操作系统集成。

是的,有三个库,而不是一个单一的整体包,这一事实使它更难使用。

但我认为这是一个值得追求的目标:如果没有强耦合,每个库都会有更多的功能。使用其中一个、两个都使用,或者两者都不使用:决定权在你。例如,Skija已经被用于AWT、LWJGL、winit等。同样的情况也适用于JWM:想要窗口管理,但自己做图形?容易的

Java的使用也使得每种JVM语言都可以使用这些功能。因此,我对分离和选择Java作为实现语言感到满意。

可以想象,在UI框架中,有很多点、向量和矩形四处飞舞。事实上,Skija和JWM也是如此。

如果有一件事我最不喜欢看到的话,那就是在结构相同但命名不同的类型之间进行毫无意义的转换。例如,从类SkijaPoint{int x,y;}到类JWMPoint{int x,y;}到(记录下位点[^int x^int y])。

a) 使用内置的AWT类。这是一个不错的选择,但可能需要与java链接。桌面模块,这是一个巨大的依赖。

b) 使用共享库。这就是我最终要做的,尽管我不想再增加一个项目。事实证明,Point和Rect几乎都是你需要分享的东西,所以它没那么糟糕,可能不需要经常更新。

Clojure有很好的Java互操作性,但它过于依赖类型注释。点和矩形真的无处不在。举个例子:

(让[content-y(-(-offset^VScroll child))content-h(-height^IPoint(-child size^VScroll child))滚动-y(-y^IPoint child rect)滚动-h(-height^IPoint cs)滚动-r(.getRight^direct child rect)

解决方案一将是(deffrecord HumblePoint[^int x^int y])。但接下来我们回到原点:从JWM点转换为Clojure点。

解决方案二是让类IPoint实现clojure。ILookup、IPersistentCollection、Associative等等。这很容易做到,可以让任何Java类的行为都像Clojure map!

这使得使用Clojure的Java类非常愉快。上面被剪掉的代码变成了

(让[content-y(-(:offset child))content-h(:height(:child size child))scroll-y(:y child rect)scroll-h(:height cs)scroll-r(:right child rect)

问题是,要实现例如clojure。你需要依赖Clojure(静态类型问题,呃)。Clojure是一个巨大的依赖性,它强加于所有想要使用Java中的Skija或JWM的人。

我在这个困境中挣扎了一段时间,直到我做出了一个相当非正统的决定:实现两个版本的类型库,一个带有Clojure接口,另一个没有。两者都包含相同的类,但后者在它们上实现了几个Clojure接口。

公共类IPoint扩展AFn实现关联{public final int_x;public final int_y;@Override public Object valAt(Object key){return valAt(key,null);}@重写公共对象调用(对象arg1){return valAt(arg1,null);}…}

Skija和JWM都依赖于类型的Clojure免费版本。但是当通过简单的UI使用时,我们已经在类路径上有了Clojure,所以我们用Clojure类型替换类型:

我对这个决定满意吗?我不知道。这听起来很复杂,我不喜欢这样。

这对于最终用户来说很简单(您依赖humbleui,默认情况下它会做正确的事情),

我喜欢使用支持Clojure的类的感觉,尽管它们是用Java编写的。

我还创建了开源软件:Fira代码、AnyBar、DataScript和Rum。如果你喜欢我所做的,并且想尽早获得我的文章(以及其他好处),你应该在Patreon上支持我。