https://kotlinlang.org logo
#javascript
Title
# javascript
r

robstoll

12/02/2023, 10:01 PM
in javascript with LEGACY backend I was able to get the implementing class/interface of an anonymous object via
Object.getPrototypeOf(obj).constructor.metadata.interfaces
. Looks like
interfaces
is no longer available in IR backend. Is there another way to work around the limited properties KClass provides in JS?
a

Artem Kobzar

12/03/2023, 6:38 AM
1. We changed the format of such information so that it is not stored as an implementation tree, which improves the performance of type checks 100 times. Still, with the new data structure (bitmask), we don't have the ability to list all the implemented interfaces. I don't think we will come back to the previous metadata. 2. And the significant addition to it. The
$metadata$
is our internal implementation detail. Please, don't use it! We change it a lot because we don't suppose that someone except the compiler uses the information. Also, we are considering removing such details for all declarations that don't use reflection.
👍 1
e

Edoardo Luppi

12/04/2023, 8:17 AM
@Artem Kobzar are/were people using that metadata mentioned in the second point? What would the benefit be in removing it? Just to understand a bit better the purpose
a

Artem Kobzar

12/04/2023, 9:09 AM
I believe that this is the metadata that @robstoll mentioned. And we would like to add it only to classes that are used with reflection just to reduce the bundle size. Right now, for the next class:
Copy code
class Foo: SomeInterface
Will be generated the the code like this:
Copy code
class Foo {
  // constructor and methods
}

setMetadata(Foo, "Foo", [SomeInterface], ...)
👍 2
e

Edoardo Luppi

12/04/2023, 9:11 AM
Ahhh yes I've seen that stuff on the outputted JS. Well, if the compiler will be smart enough to understand what we need, and what we don't need, I guess it makes sense to use it!
Ah nice, I needed to use
KClass.isInstance
and I've seen it is actually using the mentioned metadata.
Copy code
internal class SimpleKClassImpl<T : Any>(jClass: JsClass<T>) : KClassImpl<T>(jClass) {
    override val simpleName: String? = jClass.asDynamic().`$metadata$`?.simpleName.unsafeCast<String?>()

    override fun isInstance(value: Any?): Boolean {
        return jsIsType(value, jClass)
    }
}
a

Artem Kobzar

12/04/2023, 12:14 PM
Yes, because, mostly, all the things inside the metadata are needed to implement reflection and type checks. So, it's not a problem that it's used inside stdlib. We just kindly ask users to not use it directly in your code.
1
r

robstoll

12/05/2023, 6:22 AM
I was well aware that it's an implementation detail when I used it in LEGACY and wouldn't mind to use another internal with IR with all the implications it means (e.g. that you will remove it suddenly without replacement) > And we would like to add it only to classes that are used with reflection just to reduce the bundle size. Well, if that's true, then there is a bug because if you define:
Copy code
interface Foo
val o = object: Foo{}
o::class // simpleName is undefined
I'll have to check if isInstance works correctly in that case (as far as I remember, I had to add a fix in LEGACY as well)
a

Artem Kobzar

12/05/2023, 9:39 AM
But
o
is an anonymous object. What name do you expect to have in this case?
r

robstoll

12/05/2023, 12:23 PM
sorry, I must have been to tired, I for whatever reason, I though the isInstance check uses simpleName somehow 🙈 I guess there isn't a call to
setMetada
along the line of
setMetadata(o, "o$1" , [Foo], ...)
or at least the interface is missing. I can get
$o1
via JsClass.name as far as I remember
a

Artem Kobzar

12/05/2023, 12:29 PM
No. Under the hood I assign a unique number to all the interfaces, and add this numbers into a bitmask of every class that implemented the interface.
r

robstoll

12/05/2023, 12:31 PM
and store the mapping from name to number somewhere (I guess you still need it for error messages)?