librelist archives

« back to archive

:main namespace and protocols/deftypes

:main namespace and protocols/deftypes

From:
Tassilo Horn
Date:
2013-02-12 @ 15:46
Hi all,

I have a project that defines some :main namespace and provides some
command line interface there, so that I can run

    $ lein run file1 file2 ...

to process some files using the project.

The project uses some other library ("lib" in the following) that
defines several protocols and types (using deftype), and some of the
protocols are extended dynamically on the types using `extend` (or
`extend-protocol`).

Now when running the project like shown above, I got errors like

  java.lang.IllegalArgumentException: No implementation of method:
  :some-protocol-method of protocol: #'lib/SomeProtocol found for class:
  lib.SomeType

A bit debugging revealed that having a :main namespace implies doing
AOT-compilation.  In turn, the AOT-compilation compiled classes for the
deftypes, and when the project is being run, I end up with having 2
versions of any deftype classes in memory: From the AOT-compilation,
there're classes loaded by the AppClassLoader, and once I require the
lib-namespaces new classes for the very same deftypestypes are created
and loaded by a clojure DynamicClassLoader.

E.g., when I fire up a REPL using "lein repl", I get

  (map #(.getClassLoaded %) (extenders lib.SomeProtocol))
  ;=> (#<AppClassLoader sun.misc.Launcher$AppClassLoader@61a8a9e7>
  ;    #<AppClassLoader sun.misc.Launcher$AppClassLoader@61a8a9e7>
  ;    #<AppClassLoader sun.misc.Launcher$AppClassLoader@61a8a9e7>)

  (.getClassLoader (class (lib/->SomeType)))
  ;=> #<DynamicClassLoader clojure.lang.DynamicClassLoader@7842c747>

I've just found out that I can use

  :main ^:skip-aot my.main.ns

to disable AOT-compilation in the presence of a :main namespace, and
indeed, after doing that my project works again.

But is it really the case that AOT-compilation (which is at least
required for producing überjars) and dynamic protocol extension exclude
each other?

Thanks in advance,
Tassilo

Re: :main namespace and protocols/deftypes

From:
Phil Hagelberg
Date:
2013-02-12 @ 19:21
Tassilo Horn writes:

> Namespaces don't have a representation in byte-code, right?

I believe the foo/bar__init.class files are the bytecode representations
of namespaces, but I'm not sure of the details.

> I use
>
>   $ lein version
>   Leiningen 2.0.0 on Java 1.7.0_09 OpenJDK 64-Bit Server VM
>
> and apparently ^:skip-aot works.

Very strange:

    $ cd src/leiningen
    $ git checkout 2.0.0
    $ rgrep skip-aot src | wc -l # -> 0

Are you sure you're seeing this behaviour on 2.0.0 and not on an earlier preview?

-Phil

Re: [leiningen] Re: :main namespace and protocols/deftypes

From:
Stuart Sierra
Date:
2013-03-01 @ 22:23
​Jumping in late here...

Tassilo Horn wrote:
> I use
>
>   $ lein version
>   Leiningen 2.0.0 on Java 1.7.0_09 OpenJDK 64-Bit Server VM
>
> and apparently ^:skip-aot works.


Phil Hagelberg wrote:
> Very strange:
>
>     $ cd src/leiningen
>     $ git checkout 2.0.0
>     $ rgrep skip-aot src | wc -l # -> 0
>
> Are you sure you're seeing this behaviour on 2.0.0 and not
> on an earlier preview?


I've been testing with Leiningen 2.0.0, and what I see is
this:

* `lein repl` and `lein run` do NOT trigger AOT-compilation
   of :main namespaces

* `lein jar` and `lein uberjar` DO trigger AOT-compilation

* Adding `^:skip-aot` has no effect either way

-S