2024年Clojure调查中分享您的心得吧!

欢迎!请参阅关于页面以了解此如何工作的更多信息。

0票数
编译器

clojure.lang.Compiler具有以下签名的方法

public static Object eval(Object form, boolean freshLoader)

但是,由于https://github.com/clojure/clojure/commit/2c2ed386ed0f6f875342721bdaace908e298c7f3

为什么这还需要像这样“临时修复”?

我们希望为eval提供自己的ClassLoader以管理生成的类的生命周期。

4 答案

0票数

由stu发表的评论

这不是Clojure公共API的一部分。我们需要更深入地了解使用案例。

0票数

由sfnelson发表的评论

抱歉,Stuart,我们才刚刚注意到您的回复,多亏了http://ashtonkemerling.com/blog/2016/06/11/my-increasing-frustration-with-clojure/上的宣传。

我将尝试介绍我们的使用案例,以提供背景,但请理解,这个问题仅仅是关于一个看起来和感觉像公共API函数(谁能想到'eval'会是私有的)的行为的不一致。

我们公司使用Clojure构建了一个云平台,该平台通过从数据库加载模块来响应用户请求进行计算。模块是可信代码,但它们与我们主平台独立,因此可能同时运行多个相同模块的多个版本(我们希望避免命名空间冲突)。我们考虑了许多方法来防止模块相互干扰,包括运行单独JVM的容器和微服务,但为了使简单查询(如“此输入是否有效?”)有可接受的反应时间,我们希望在Web服务器相同的JVM中运行简单查询。

我们用于响应用户查询的一般方法是为我们的计算构建一个命名空间(这可能需要从计算模块加载其他命名空间),然后在构建的上下文中评估表达式。我们有一个LRU缓存来存储模块命名空间,但评估仍然会产生大量元空间抖动,我们通过使用Clojure解释器来处理简单查询(评估太慢)来减轻这一现象。

当实现我们的LRU模块命名空间缓存时,我们想尝试将模块命名空间加载到自己的类加载器中,以帮助追踪类生命周期和GC,并希望允许多个命名空间版本并存。但后来我们得出结论,这是行不通的,因为Clojure与命名空间相关的全局查找太多,所以我们现在在加载时对模块命名空间进行预处理并执行名称混淆,并在缓存过期时显式注销已加载的命名空间,以便它们的类可以被收集。我们避免在模块中使用像multimethods和protocols这样的语言功能,它们使用全局变量。

再次,我们并不是在寻找Clojure团队为我们实现容器(尽管这肯定是一个很好的功能!),这只是我们注意到API和实现之间的一个不一致性。Java-interop eval的预期入口点是什么?

0票数

评论人:alexmiller

您可以使用Clojure Java API,有关文档,请参见 http://clojure.github.io/clojure/javadoc/clojure/java/api/Clojure.html

以下是一个基本示例,它从Java字符串中读取和评估代码:

`
import clojure.java.api.Clojure;
import clojure.lang.IFn;

// ...

IFn read = Clojure.var("clojure.core", "read-string");
IFn eval = Clojure.var("clojure.core", "eval");

Object code = read.invoke("(+ 1 1)");
Object result = eval.invoke(code);
System.out.println("read: " + code + ", eval: " + result);
`

不过,您可以做更复杂的事情,例如生成一个命名空间字符串并使用相同的机制调用{{load-string}}。

0票数
参考: https://clojure.atlassian.net/browse/CLJ-1463(由ale+import报告)
...