请在 Clojure 2024状态调查中分享您的想法!

欢迎!请参阅关于页面了解有关此功能的一些更多信息。

0 投票
编译器

clojure.lang.Compiler有这样一个方法签名

public static Object eval(Object form, boolean freshLoader)

但是鲜活的加载器参数被忽略了,因为https://github.com/clojure/clojure/commit/2c2ed386ed0f6f875342721bdaace908e298c7f3

这个还需要这样“热修复”,有什么好理由吗?

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

4 答案

0 投票

由stu发表的评论

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

0 投票

由sfnelson发表的评论

对不起,斯图尔特,我们刚刚注意到您的回复,多亏了http://ashtonkemerling.com/blog/2016/06/11/my-increasing-frustration-with-clojure/的公开。

我将尝试解释我们的使用-case以提供一些上下文,但请理解这个问题只是关于一个看似是公共API函数的功能(谁能想到'eval'是私有的呢?:)

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

我们回答用户查询的一般方法是建立一个计算命名空间(可能会加载计算模块中的其他命名空间),然后在创建的上下文中评估该表达式。我们有一个用于模块命名空间的LRU缓存,但评估仍然导致大量的元空间震荡,我们使用Clojure解释器来处理简单查询(评估速度太慢)来解决这个问题。

当我们实现我们的LRU模块命名空间缓存时,我们想要尝试将模块命名空间加载到自己的类加载器中,以帮助跟踪类生命周期和GC,并希望允许多个命名空间版本共存。但我们已经得出结论,这种方法不切实际,因为Clojure有大量的与命名空间相关的全局查找,所以我们现在在加载时预处理模块命名空间并对它们进行重命名,并在缓存过期时显式注销加载的命名空间,以便它们的类可以被收集。我们避免使用在模块中使用全局变量的多态方法和协议等语言功能。

我们再次不是在寻求Clojure团队为我们实现容器(尽管那确实是一个美好的功能!),这只是一个我们注意到API和实现之间不一致性的例子。Java互操eval的预期入口点是什么?

0 投票

评论者:alexmiller

您可以使用在http://clojure.github.io/clojure/javadoc/clojure/java/api/Clojure.html中记录的Clojure Java API。

以下是一个基本示例,它从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](https://clojure.atlassian.net/browse/CLJ-1463) (由alexmiller报告)
...