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缓存用于模块命名空间,但我们最终仍然会因为评估而在元空间产生大量的 churn,我们通过使用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("读取: " + code + ", 计算结果: " + result);
`

然而,您还可以做一些更复杂的事情,例如生成一个命名空间字符串并使用上面相同的方法调用{{load-string}}。

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