I have two questions about Compiler.resolveSymbol .
First question: Well, this one actually has two parts. Looking at
static Symbol resolveSymbol(Symbol sym){
//already qualified or classname?
if(sym.name.indexOf('.') > 0)
return sym;
if(sym.ns != null)
{
Namespace ns = namespaceFor(sym);
if(ns == null || (ns.name.name == null ? sym.ns == null : ns.name.name.equals(sym.ns))) // <==== LOOKING AT THIS
{
1a. The expression ns.name.name == null tests a whether Namespace whose name , a Symbol, has a name which is null? One has to work to create a symbol with a null name. That seems unlikely to occur when creating a namespace. Under what circumstances would we find such a Namespace? I understand that this test is like to protect the ns.name.name.equals call that follows in the else,s so I'm guessing this is just defensive programming. However, see next.
1b. In the context where the conditional expression (ns.name.name == null ? sym.ns == null : ns.name.name.equals(sym.ns)) occurs, we already know sym.ns is not null. so the then of the conditional is false. So the conditional is actually (A ? false : B) which would reduce to (not A and B). Is there a reason this is coded the it is? Was something else intended?
In other words, putting 1a and 1b together, was the intent just
if ( ns == null || (ns.name.name != null && ns.name.name.equals(sym.ns) ) ...
(even thought the possibility of actually encountering ns.name.name == null is zero)?
Second question: Immediately following the lines above, we have
Class ac = HostExpr.maybeArrayClass(sym);
if(ac != null)
return Util.arrayTypeToSymbol(ac);
return sym;
if sym has the form ns/digit then HostExpr.MaybeArrayClass converts the ns to a type (and throws if we fail) and then construct an array type with an appropriate degree of array-ness (to coin a phrase). Notably for this discussion, if sym was int/2 there is a step to convert the int to int.class so we have the base element type for the array class.
Util.arrayTypeToSymbol reverses this. For primitive types, you get back what you started with. For other types, you might get the fully -qualified name back:
(namespace `int/2) ; => int
(namespace `String/2) ; => java.lang.String/2
Compiler.resolveSymbol is called only by LispReader.SyntaxQuoteReader.syntaxQuote, so the expansion of String to java.lang.String is in line with the contract for syntax-quote ("...syntax-quote resolves the symbol in the current context, yielding a fully-qualified symbol (i.e. namespace/name or fully.qualified.Classname.")
However, closer examination is raises some questions. The conversion in the second line is not done by the code in question. The context for the call to resolveSymbol in this case:
{
Object maybeClass = null;
if(sym.ns != null)
maybeClass = Compiler.currentNS().getMapping(
Symbol.intern(null, sym.ns));
if(maybeClass instanceof Class)
{
// Classname/foo -> package.qualified.Classname/foo
sym = Symbol.intern(
((Class)maybeClass).getName(), sym.name);
}
else
sym = Compiler.resolveSymbol(sym);
}
With String/2, there is a mapping in the current namespace from String to the type java.lang.String , so we do not call resolveSymbol in this case.
We are only going to call resolveSymbol when there is no mapping.
If we call resolveSymbol on something like java.beans.EventHandler/2 , we're going to get back java.beans.EventHandler/2
When resolving something like int/2 , we're going to back int2.
So my question becomes this. Looking at this chunk of code:
if(sym.ns != null)
{
Namespace ns = namespaceFor(sym);
if(ns == null || (ns.name.name == null ? sym.ns == null : ns.name.name.equals(sym.ns))) // <==== LOOKING AT THIS
{ // <<<
Class ac = HostExpr.maybeArrayClass(sym); // <<<
if(ac != null) // <<<
return Util.arrayTypeToSymbol(ac); // <<<
return sym; // <<<
} // <<<
return Symbol.intern(ns.name.name, sym.Name);
}
Given that anything like String/2 which has a mapping in the current namespace for its namespace is not going go through this code.
Under what circumstances will the indicated code return anything but the sym, either that symbol itself or a duplicate?
I think it can only be the case where you can find a type from the namespace of sym (that ultimately comes down to what RT.classForName can find) but the fully-qualified name of the type is different. Can this happen? (Likely my Java ignorance is showing.)this question is so big it's like 2+ screens high for me which makes it much harder to read and answer at the same time. if you could break it up next time, that would help.
on the logic thing at the top, that is known to be gross, and certainly would be good to clean up, don't know the history. But I believe the intent of the condition is "is this qualified symbol ok as is", either because it's a host symbol or a fq namespaced var. If so, then return sym unchanged (other than new array case), else return fq namespaced var.
the new code for array classes (previously invalid symbols) is a further refinement here - if it's of the form FOO/[0-9] then that is an invalid symbol unless it's an array class, and in that case we do the work to FQ it (or throw if we can't resolve the class). An important side effect of the maybeArrayClass is that if the symbol is of the array class form, but not a resolvable component type, it will throw, so this is a validation step.
@fogus might have more to say here
I think Alex covered it well, so not much to add. The main takeaway on my approach to making these changes was to disrupt existing code as little as possible. There's a lot of nuance in the way that the code works and a lot of existing code that depends on it.
My reason for bringing these points up is to make sure I understand things enough that I don't break things myself.
When I ported from Java to C#, I could mostly copy and not think about it.
I even preserved if (initProvided || true)//includesExplicitMetadata((MapExpr) meta)) ...
The discipline imposed by rewriting in F# has forced me to understand things I of which I had been happy to remain ignorant.
Even if the F# code never sees the light of day, the exercise is helpful to me.
But some degree of PITA for you folks. Sorry. Appreciations.
I for one Iām happy to help however I can. Thank you for your efforts.
i'm just an outside observer but i love reading these questions
helps me understand what's going on in the compiler