Continuing my sequence of annoying compiler questions:
1. In TryExpr, why are hasJavaClass and getJavaClass computed from tryExpr only? Catch clauses also can return values; those values do not have to agree with tryExpr. I realize Clojure is not very strict about these things, but for example one might be misled into doing an explicit method call rather than reflection. (`TryExpr` is not a MaybePrimitiveExpr, so at least we don't have to worry about primitives here.)
2. Why is there a tag field in ObjExpr? (And by inheritance, FnExpr and NewInstanceExpr .) The only places it is referenced are ObjExpr.getJavaClass and its override in FnExpr.getJavaClass. During the loading of the entire corpus of Clojure source code, the tag is always null. During the load, the FnExpr.getJavaClass method is called, but in only three contexts: (a) we are checking if it is a primitive type (not) -- this most often occurs when an fn is the binding of a local; (b) we are trying to access the __methodImplCache field (in which case we need to be an AFunction which is the default for FnExpr.getJavaClass when no tag is present), and (c) some case statements in the spec code where the return values in the cases are all fns. Is there some circumstance where the tag would be used?
3. Let's dig in a little deeper. The code for ObjExpr.hasJavaClass is
Class jc;
public Class getJavaClass() {
if (jc == null)
jc = (compiledClass != null) ? compiledClass
: (tag != null) ? HostExpr.tagToClass(tag)
: IFn.class;
return jc;
}
This is overridden in FnExpr (more on that in a moment), but used as is by NewInstanceExpr. compiledClass is set by getCompiledClass, which is called during parsing by both FnExpr and NewInstanceExpr. I cannot identify a situation where this ObjExpr.getJavaClass can be called when compiledClass is null. (Thus rendering the tag completely useless -- we'll never check it.) It is true that the nascent ObjExpr is passed down into the method parsers, but only to intialize a field in the method, not otherwise used. Have I missed something? Defensive programming?
4. FnExpr overrides ObjExpr.getJavaClass with this:
public Class getJavaClass() {
if (jc == null)
jc = tag != null ? HostExpr.tagToClass(tag) : AFunction.class;
return jc;
}
The use of compiledClass has disappeared. Why does this matter? 1. shouldn't you use the "normal" return as the source of the hinted return type? they don't have to match (in reality the try expr is always returning Object). this seems right to me, just logically. 2. I've run into this before, and iirc I think it's vestigial, but not sure. 3. don't know, you're probably right 4. don't know
1. My plan for the ongoing work in ClojureCLR.Next is to have a mode where typing is more strict. The goal is to properly deal with value types and making sure one can write code with no unnecessary boxing. So I have to know when I get out of a construct at minimum whether I have a reference type or value type sitting there. (I do plan on having a 'classic' or 'compatibility' mode that sticks with the current semantics. In particular, for TryExpr, I need to know what's coming out of all branches. I figured it didn't matter here because TryExpr is not a MaybePrimitiveExpr and hence does not participate in any long/double games 2. (and 3 and 4). Thanks. As usual, I work from the assumption that everything is the way it is for a reason and I'm just too dense. (However, when I hit the three-hour mark in trying to figure something out, I start to think maybe it isn't just me) At the moment, as you likely can guess, I'm trying to figure out all the ways type hints propagate through the system. (FnMethod and I are definitely not on speaking terms anymore.)
sorry for not replying to the earlier ones, tend to miss stuff on the weekend. I haven't looked into them, not sure when I will have a chance, these kinds of questions usually take some archaeology and often the answer is more a side effect of a series of changes over time rather than intention.
I'm appreciative of the time you have spent already. I realize most of these questions are in negative-payoff territory. And that some things are likely vestigial. On some of these, I go back in history to see if I can figure that out -- blame in github is my best friend -- but still can't always make a determination.