Great breakdown.

1. "compile and bootstrap yourself through gen-class" means: you generate a 
> class and then invoke the main() method of that class
>

I'd go further then just calling main. So I mean you generate a class, and 
every function call from Java using the generated class should be executed 
as if it were executed through clojure.main, so with the bindings set and 
inside the user namespace.
 

> 2. "loaded at runtime" means: you (presumably) start the REPL, load a 
> namespace (either from a source file or a class file), then invoke the 
> -main function
>

Correct. It's the case of a non AOT compiled namespace being loaded from 
one of the many (load) functions of Clojure. Such as:

(load "dda/main")
(dda.main/-main)
 

> 3. "bootstrapped through clojure.main" means: you invoke clojure.main (a 
> compiled program provided with Clojure) with the -m arg specifying a 
> namespace. This will start the Clojure runtime, load the namespace, then 
> invoke the -main function
>

Correct.
 

> 4. "bootstrapped through lein" means: I assume this is "lein run" with a 
> :main set or "lein run -m" but I think lein supports specifying a namespace 
> or a function in a namespace or a class with a main() method. Depending 
> which of those you're doing, this is like similar to either #1 or #2 and 
> here lein is effectively doing similar work as #3.
>

Correct, yes internally lein delegates to clojure.main I believe.
 

> 5. There is a Clojure Java API (http://clojure.github.io/clojure/javadoc/), 
> but I'm not sure if you are actually referring to this or something else. 
> Doing so would basically mean going through that API to do the same thing 
> as #2. 
>

I am talking about that API. I believe it uses RT under the hood, and ends 
up doing the same thing that #1 does. So in my test, if you did:

IFn require = Clojure.var("dda.main", "-main");
require.invoke();

This will run inside "clojure.core", and will not have any of the default 
bindings set available.

I think if I were to restate your suggestion, I would say that a 
> genclass-compiled main entry point should initialize the Clojure runtime 
> and invoke the code in a binding as if it were being invoked from other 
> Clojure code. I can see some logic in that (although that then also affects 
> #3 and #4 as they go through this code too).
>

Ya, arguably, I wonder why the clojure runtime doesn't initialize the 
bindings and sets the namespace to 'user before delegating execution back 
to user code. If it did, then every invocation of Clojure from Java would 
always be bootstrapped in a similar way, and run under an equal context. 
Clojure.main wouldn't need to do it anymore.

But there might be a good reason for not doing that inside the clojure 
runtime. In which case, it still leaves open the question of should clojure 
invocations through a generated class, and invocations from the Clojure API 
mimic the bootstrapping of clojure.main?


P.S.: I also know that in practice, this has not caused that many issues, 
due to the fact that Clojure is now many years old, and I've never heard of 
other people complain about the discrepancies between generated classes and 
the clojure API versus clojure.main. So I don't think its a pressing issue, 
but I still feel it could be worth a thought.


On Wednesday, 21 June 2017 09:19:59 UTC-7, Alex Miller wrote:
>
>
>
> On Wednesday, June 21, 2017 at 9:42:00 AM UTC-5, Didier wrote:
>>
>> I think I answered myself, looks like it does here:
>>
>> try {
>>                   Var.pushThreadBindings(
>>                                 RT.mapUniqueKeys(CURRENT_NS, CURRENT_NS.
>> deref(),
>>                                               WARN_ON_REFLECTION, 
>> WARN_ON_REFLECTION.deref()
>>                                                   ,RT.UNCHECKED_MATH, RT.
>> UNCHECKED_MATH.deref()));
>>                        loaded = (loadClassForName(scriptbase.replace('/', 
>> '.') + LOADER_SUFFIX) != null);
>>              }
>>               finally {
>>                       Var.popThreadBindings();
>>                }
>>
>>
>> So now I understand, but I wonder if it makes sense. 99% of the time, it 
>> won't be an issue, but if you're doing anything with *ns*, you'll run into 
>> a situation where if you compile and bootstrap yourself through gen-class 
>> or clojure's java API, your code will not behave similar to when you're 
>> loaded at runtime or bootsraped through clojure.main or lein.
>>
>
> It would be helpful to be clearer about what you mean with these different 
> cases as it's ambiguous to me at least. I think you mean:
>
> 1. "compile and bootstrap yourself through gen-class" means: you generate 
> a class and then invoke the main() method of that class
> 2. "loaded at runtime" means: you (presumably) start the REPL, load a 
> namespace (either from a source file or a class file), then invoke the 
> -main function
> 3. "bootstrapped through clojure.main" means: you invoke clojure.main (a 
> compiled program provided with Clojure) with the -m arg specifying a 
> namespace. This will start the Clojure runtime, load the namespace, then 
> invoke the -main function
> 4. "bootstrapped through lein" means: I assume this is "lein run" with a 
> :main set or "lein run -m" but I think lein supports specifying a namespace 
> or a function in a namespace or a class with a main() method. Depending 
> which of those you're doing, this is like similar to either #1 or #2 and 
> here lein is effectively doing similar work as #3.
> 5. There is a Clojure Java API (http://clojure.github.io/clojure/javadoc/), 
> but I'm not sure if you are actually referring to this or something else. 
> Doing so would basically mean going through that API to do the same thing 
> as #2. 
>  
>
>>
>> (ns dda.main
>>   (:gen-class))
>>
>> (def should-exist "Do I exist?")
>>
>> (defn -main []
>>   (in-ns 'other)
>>   (ns-name *ns*))
>>
>> A bad example, but this code will work through lein, clojure.main, and 
>> when loaded from a REPL, but not when started from gen-class or Clojure's 
>> java API. Is there a good reason for the discrepancy? 
>>
>
> You are doing different things, and thus experiencing different results, 
> so in some sense I would expect them not to be identical. In particular, 
> both #3 clojure.main and #4 Leiningen are effectively programs wrapping 
> your program - since you're using a wrapper, you should expect that wrapper 
> to do more stuff and have an effect on your runtime environment. What I 
> think maybe is interesting here is the difference between invoking a main() 
> method first vs loading and invoking the function from the Clojure runtime 
> (#1 vs #2). There you see that some things are bound in #2 that have not 
> yet been bound in #1. More below at the end.
>  
>
>> Shouldn't all methods to bootstrap your code start out with an equal 
>> initialization scheme? 
>>
>
> Maybe. We are also interacting with the host initialization here and that 
> complicates things. The only way to start a Java program is ultimately to 
> specify a class with a main() method, so that's a constraint we have to 
> deal with.
>  
>
>> I would suggest that Clojure's java API (which I assume gen-class uses 
>> under the hood)
>>
>
> Again, I'm struggling to connect "Clojure's Java API" here to what that 
> means to me. gen-class is not involved at runtime - it's compile-time 
> functionality that produces a class file. That generated class file uses 
> the *Clojure runtime* to load and invoke Clojure functions. Most of that is 
> exactly the same as what happens when running typical Clojure functions. 
> The part that's different is that there is some additional scaffolding 
> created to handle the namespace-level effects when loading AOT classes.
>  
>
>> should also initialize the common bindings and set the namespace to user. 
>> That way, all entry point always behave similarly.
>>
>
> I think if I were to restate your suggestion, I would say that a 
> genclass-compiled main entry point should initialize the Clojure runtime 
> and invoke the code in a binding as if it were being invoked from other 
> Clojure code. I can see some logic in that (although that then also affects 
> #3 and #4 as they go through this code too).
>
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to