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投票

Comment made by: stu

这并不是 Clojure 公共 API 的一部分。我们需要了解更多关于用例的信息。

0投票

Comment made by: sfnelson

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

我将尝试解释我们的用例,以便提供一些背景信息,但请理解,这个问题仅仅是一个关于看起来像是公共 API 函数(谁知道 'eval' 会是私有的 :-)的不一致行为的问题。

我们公司使用Clojure来构建一个云计算平台,该平台根据用户请求在数据库中装载数模块执行计算。模块是受信任的代码,但它们与我们的主平台是独立的,因此同一时间可能会运行相同模块的多个版本(我们想避免命名空间冲突)。我们已经研究了多种方法来防止模块相互干扰,包括运行在分离JVM中的容器和微服务,但为了保证简单的查询,例如“这个输入是否有效?”的可接受响应时间,我们希望在运行在Web服务器同一个JVM上执行简单查询。

我们回答用户查询的一般方法是为我们的计算创建一个命名空间(这可能需要从计算模块加载其他命名空间),然后在构建的上下文中评估表达式。我们有模块命名空间的LRU缓存,但评估过程中仍然产生了大量元空间的碎片,我们通过使用clojure解释器来处理简单查询(eval速度过慢)来缓解这一问题。

在实现我们自己的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 (由alex+import报告)
...