简体   繁体   English

如何使用循环类型提示对gen-class类进行aot编译?

[英]How to aot-compile gen-class classes with cyclic type hints?

In Clojure, I'm using gen-class with a Java library. 在Clojure中,我将gen-class与Java库一起使用。 The programmer normally provides two classes that implement an interface and extend a class, respectively. 程序员通常提供两个类,分别实现一个接口和扩展一个类。 The two classes are supposed to refer to each other, and it's hard to avoid this cyclic dependency given the way the library is designed. 这两个类应该相互引用,并且鉴于库的设计方式,很难避免这种循环依赖性。

The cycles wouldn't be a problem--the compiler doesn't have to know about them--except that I'm trying to optimize the code by judiciously adding type hints (with huge speedups). 周期不是问题-编译器不必了解它们-除非我试图通过明智地添加类型提示(以大幅度的加速)来优化代码。 I've been able to avoid compiler complaints about cyclic dependencies by reorganizing the code, and I've reduced the problem to a single type hint: 通过重组代码,我能够避免编译器抱怨循环依赖,并将问题简化为单个类型提示:

In one source file, Foo.clj, I have this function/method, which is required by the interface the class implements: 在一个源文件Foo.clj中,我具有此函数/方法,该方法/方法是类实现的接口所必需的:

(defn -step
  [^Foo this ^Bar bar]
  ...)

Another source file, Bar.clj, creates a collection of instances of Foo, so I have to refer to the Foo class there. 另一个源文件Bar.clj创建了Foo实例的集合,因此我必须在此引用Foo类。 In my Leiningen project.clj, I have a line like this: 在我的Leiningen project.clj中,我有这样一行:

:aot [Foo Bar]

I don't get a cyclic dependency error. 我没有周期性的依赖错误。 Instead I get a ClassNotFoundException : If I put Foo first after :aot , the compiler complains that it doesn't know about Bar when it compiles Foo , because of the ^Bar type hint in -step . 相反,我得到ClassNotFoundException :如果我将Foo放在:aot ,则编译器会抱怨它在编译Foo时不了解Bar ,因为^Bar类型提示在-step If I put Bar first after :aot , the compiler can't find Foo when it compiles Bar , because of the calls to (Foo.) in Bar.clj. 如果我将Bar放在:aot ,则编译器在编译Bar时找不到Foo ,这是因为Bar.clj中对(Foo.)的调用。

My current solution is this: 我当前的解决方案是这样的:

  1. Delete the ^Bar type hint in the definition of -step in Foo.clj. 删除^Bar类型暗示的定义-step在Foo.clj。
  2. Compile both classes. 编译两个类。
  3. Add the type hint back in -step in Foo.clj. 添加类型提示回-step在Foo.clj。
  4. Compile Foo (ie run 'lein compile` again). 编译Foo (即再次运行“ lein compile”)。

This works because when Foo is compiled the second time, Bar exists, so the compiler doesn't complain. 之所以可行,是因为第二次编译Foo时, Bar存在,因此编译器不会抱怨。

Is there a way to compile both classes without deleting and adding back the type hint? 有没有一种方法可以编译两个类而又不删除并重新添加类型提示? (Or a different way that I should think about this situation?) (或者我应该考虑这种情况的另一种方式?)

My inclination would be to add a factory function for Foo in the foo namespace. 我的倾向是在foo名称空间中为Foo添加一个工厂函数。

(defn new-foo [] (Foo.)) ; parameterize to your satisfaction

And then you could use the forward declaration technique in the following answer to get access to new-foo from Bar - Forward-declaring a var from another namespace in Clojure? 然后,您可以在以下答案中使用前向声明技术来从Bar中访问new-foo-从Clojure中的另一个命名空间中前向声明var?

This is of course still icky - if there's any other way to break the dependency cycle you might take it. 当然,这仍然很棘手-如果还有其他方法可以打破依赖关系循环,则可以采取这种方法。 How about defining Foo and Bar in the same namespace if it makes sense? 如果可以的话,如何在同一个命名空间中定义Foo和Bar? They do seem very tightly coupled, although with an abstract problem description it's hard to tell. 它们看起来确实紧密耦合,尽管很难用抽象的问题描述来说明。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM