Are we still unable to get fully qualified class n...
# javascript
t
Are we still unable to get fully qualified class names in JavaScript? Is it planned in the future?
a
Could you describe your use-case? Are you talking about the reflection?
o
I’m relying on fully qualified class names for logging (and other telemetry). Actually I want to identify the scope. It would be ideal to just obtain the fully qualified name of the nearest enclosing scope. For the top-level scope this would be the fully qualified name of the „file class“ (as present on the JVM).
Details and resolution approach: https://github.com/JakeWharton/cite/issues/19
t
@Artem Kobzar There could be many use cases for this. Just for an example: kotlinx.serialization uses the fully qualified name for polymorhpic serialization if you do not specify otherwise. Of course, they use their own compiler plugin to get it. Other example would be having UI widget registries. For me, right now it is the translation of UI texts. To do it properly, I need the qualified name. Among other things I want my enums to be translated automatically, based on a translation managed by the administrators on server side. Now, I am very lazy when writing business level code. Therefore I will just put the getting of the qualified name into my compiler plugin thus solving the problem.
a
I see. We are discussing this with our team, and we are a bit scary about the bundle size increasing with saving every qualified name.
o
If a compiler intrinsic provided the qualified name, the bundle would just have to store names which were actually accessed, right?
c
> If a compiler intrinsic provided the qualified name, the bundle would just have to store names which were actually accessed, right? In that case,
Copy code
package foo

interface A
class B : A

val a: A = B()

println(a::class.qualifiedName) // foo.A
on the JVM, it would print
foo.B
Maybe the compiler could be clever enough to only generate qualified names for subtypes of variables on which
::class.qualifiedName
is called? But that would probably break if an app tries to access the qualified name of a type from a library, which didn't use it itself
t
The bundle size is a valid concern (especially with all the miniature value classes). However, not having the option to work with the qualified name in any ways forces developers to find other solutions. Which in turn will also increase the bundle size. For example the qualified names could be used for on-demand loading and lazy binding of packages which would in turn dramatically decrease the bundle size with a proper structure. What I do is that I add the qualified name to the class when it implements a specific interface. This way I have it when needed but not when it is unnecessary. For translations this is typically a few interfaces, objects, enums and a number of data classes. My other option would be to manually add all the labels for all the fields, for all the table headers, for all the enumerations etc. That is much-much more code than the one lonely string. Not to mention that it is error-prone, very hard to collect all the things I have to translate etc. @CLOVIS May cases, the compiler does not now the name of the class at compile time. For example, if the parameter of your function is an interface, you have no idea what the class will be during runtime.
o
@CLOVIS True, my suggestion would always resolve statically. This would be sufficient to cover my use cases (and I'd actual prefer this over dynamically resolving magic). I'm currently using a compiler plugin, which initializes an annotated parameter with the fully qualified name of the nearest enclosing call-site class:
Copy code
@Qualifiable
fun logger(@QualifiedClassName qualifiedName: String = "")
t
While for logging the static solution is fine, there is no need for dynamic resolution in general. For example, I simply declare a field in the interface. The default implementation is there so the IDE does not complain about the missing override.
Copy code
interface Qualifiable {
    val qualifiedClassName : String get() = TODO()
}
Then the plugin overrides the field as below. It is not dynamic, it is the same as you would hardcode it manually. Not the best solution, but this is what I was able to reach with reasonable effort.
Copy code
package a.b

class A : Qualifiable {
    override val qualifiedClassName = "a.b.A"
}
Truth to be told, I'm not a big fan of annotations, especially on parameters.
o
(I'm not a big fan of magic, and annotations often come along with that.) In my above example, the main point is that I don't have to mark each class in order to obtain its qualified name. I just annotate the logger function – a single place in the entire code base.
t
Well, all technologies advanced enough seem like magic. 🙂 But I agree, for your use case the in-line annotation is a good solution.