QML/JS aliases vs. imports

Milian Wolff mail at milianw.de
Thu Jul 10 12:28:15 UTC 2014

Hey all,

let us move the discussion here.

I asked:

> Furthermore, unrelated to this review request, could you explain me again
> why you create alias declarations instead of importing the context of the
> imported file into the namespace/class context? 

Denis answered:

> Regarding aliased declarations, I first tried to import the context of the
> file in the namespace, but then I discovered that I needed some sort of
> filtering. For instance, when importing a file, the namespace alias
> declarations of this file should not be imported (typing "MyFile." should
> offer completion items for every local declaration of MyFile, but not for
> "MyFile.QtQuick", "MyFile.MyOtherFile", etc).

Me again:

> Regarding alias declarations: we should rethink that and probably filter it
> in the code completion then, instead of spamming the duchain with alias
> declarations.


> Does "MyFile.QtQuick.Foo" work in theory? If yes, then I certainly agree
> with Milian that the filtering should take place in the completion list.


> I remember having played with addImportedParentContext, namespaces and
> automatic imports, and I remember that using alias declarations was a last
> resort solution. Until just now, I did not remember what was the problem,
> though :-).
> Now I have remembered what it was:
> http://steckdenis.be/post-2014-06-17-qml-module-versions-and-automatic-impo
> rts.html (first title, fourth paragraph) :
> There is a small technical difficulty here, though: if every file imports
> all the others, we get circular dependencies (A imports B and C, but B
> imports A and C, thus A can see itself by the way of B). The solution that
> I used is to “copy” the declarations of every file into the others instead
> of importing them. This way, A doesn’t import anything but contains the
> declarations of B, C, etc. B does the same, but uses the version of A
> without the declarations of B, C, etc copied. This way, A cannot see itself
> by the way of B, and B cannot see itself by the way of A.
> Using clearer and more technical words, I have a problem when unnamed
> imports are used (the automatic import of the files in the same directory,
> and imports without an "as" clause). Let's take three files: A, B and C.
> Let's say that B and C are in the same directory, and that A contains an
> "import B as B" statement.
> If addImportedParentContext is used, then the top-context of B will import
> the top-context of C (because they are in the same directory). The
> top-context of C will import the top-context of B, which will create a
> cyclic import (very difficult to solve, because both B and C should be able
> to see the declarations of the other file, but that could be worked around
> using namespaces and {...import...} namespace aliases). This is the first
> problem.
> Now, A imports B, because A is interested in the declarations of B. If A
> creates a namespace named B (because there was an "as B" clause in the
> import), and imports the top-context of B in this namespace, then every
> declaration visible from the top-context of B will be available in the
> namespace B. The problem is that B sees the declaration of C, so the
> declarations of C become visible in the namespace "B", that should only
> contain the declarations of B. This is the second problem.
> Using alias declarations, I can copy only the local declarations of the
> context I import. This avoids circular imports (A imports the declarations
> of B, no matter which declarations B can have imported, because aliased
> declarations are filtered out), and ensures that importing a file only
> imports the file and not everything else it may have imported itself.
> Maybe a better solution exists for these two problems. I'll think about it,
> but the solution used depends on the importance you give to concise code
> (alias declarations require less than 10 lines of code and work well) and
> clean DUChain (alias declarations fill the DUChain, and using nested
> contexts or namespace aliases could simplify the DUChain at the expense of
> code complexity).

Yes, only import what you need. If you only want to import everything, always, 
just to get code completion, you do it wrong imo. Instead, you can offer, 
during code-completion, all "public" items from other files in the same 
folder. In the DUChainBuilder, when you encounter a use of an unknown 
declaration, you ask the persistent symbol table for a file that declares it. 
Or just go over the files in the same folder. Then, if you find something 
viable, add an import for that file to the topducontext you are currently 
parsing and connect the use.

This is what PHP is doing for years and works quite nicely. Spamming the 
DUChain in the way you do will easily lead to extremely large caches and may 
also degrade performance quite a bit. With the above, you only pay for things 
you use. And the extra cycles during code completion are OK as well, imo. If 
it turns out to be problematic, we could/should think about sharing some code 
for the special index that PHP uses to speed up its code completion.

Milian Wolff
mail at milianw.de

More information about the KDevelop-devel mailing list