Reflection?


#1

One of the reasons we are investigating Kotlin is because of the announced support for native targets using LLVM.

Will Kotlin/native have a complete implementation of reflection? Will it Include the missing parts that are now only available from the JRE (for example, java.lang.Class)?

I realize that reflection is not a simple thing to implement with an LLVM target. But I need to understand about what is planned and will it be sufficient for our needs.

Is there an overview or planning document that is available to me that outlines the limitations and differences between Kotlin/JVM and Kotlin/native?

TIA.


#2

Kotlin/Native will support a very limited reflection only (callable references, etc) and will unlikely to support full introspection (list available class properties, methods, etc) in its initial release. However, as Kotlin/Native is a research project, we are very interested in all the potential use-cases for it. Can you share here what are your use-cases for reflection, please?


#3

I will try to list reflection features I use in the order of importance (most important first):

  1. Instance checks (is operator). Class object and ability to check instance class against given class. Kotlin native will probably overcome problem of type erasure, so it will in some cases allow not to store class instance, but it still is very useful.
  2. Instantiation via reflections (call default or non-default constructor). It is required for use of service providers, serialization etc.
  3. Class annotations in runtime! Modern Java uses it a lot.
  4. Method annotations. Search for a method with given annotation in runtime.

#4

Thanks for feedback!

  1. We do not consider this to be reflection, but a type-system (in Kotlin) and it already works.
  2. This is unlikely to be supported, but serialization for K/N will be provided separately in a static way (without having to go through reflection).
  3. This is unlikely to be supported in the initial release.
  4. – " –

#5

The key feature that is missing from kotlin.reflect is java.lang.Class.forName(String).

We use forName( ) in a variety of patterns in library code. One pattern is to provide implementations of interfaces at runtime that can’t be known at compile time (probably what darksnake’s point 2 refers to). Another important pattern is that for certain application classes (not library code), the library code checks to see if an additional class exists with the same name except we insert “.generated” into the package name structure (those classes are machine generated, not hand-coded). It is correct as far as the library API is concerned for the generated class to exist or not exist in any given invocation of the application. The concept of the generated class existing or not existing is as simple as adding or removing it from the .jar file, or simply removing a .jar file from the classpath of the invocation. No packaging tool creating bundles with permutations of classes included is used - the .generated class either exists or doesn’t exist at runtime and that’s fine.


#6

The initial release of K/N will definitely not support Class.forName. The whole idea of K/N is to provide a “closed world” view of the code and enable to build a highly-optimized and compact executable. We believe that use-cases that require reflection in the way that you’ve described are perfectly covered by Kotlin/JVM already. We are not trying to build a better JVM.


#7

I understand, although I don’t need special class loaders or other stuff the JVM provides. I can make my library work with a more complex packaging at invocation mechanism that has a step to create a lookup translation from String literal to ::class syntax. It’s cumbersome, but I already did it for Swift because they have no reflection capabilities whatsoever. I was hoping to have portable code both inside and outside my library that runs on JVM, Android and iOS. It appears that Xamarin/Microsoft/C# is a better solution in this regard, which is unfortunate as I simply do not trust Microsoft to the level that I will simply avoid them at all costs.

And FWIW, I think you are making a mistake by using reference counting for garbage collection. At some point you will need mark and sweep or something else to pick up the cyclic references. And please do not introduce the variety of reference types (unowned, weak, strong, etc.) that exist in Swift because of ARC - it’s an application programmer’s nightmare.


#8

The current version of Kotlin Native is in fact using a garbage collector to sweep up cyclic references, given that ARC can’t deal automatically with them and the unpleasantness of the alternatives.

I don’t think they’ve ruled out possibly using a tracing GC for those native platfforms where this is feasible but unfortunately iOS is not one of them.


#9

We are not trying to compete with VMs (both JVM and Mono). They both do their jobs quite well. We don’t feel we can offer anything unique in VM space at this moment. The plan for K/N is to run without VM, while still allowing for a portable code. Yes, you’ll have to generate some sources for the use-case you have in mind, bit the upside is that those sources will be portable accross all Kotlin platforms. If that is a burden, then I’d suggest using Kotlin/JVM which has quite comprehensive reflection facilities.


#10

What about just being able to use KClass<*> as key in a map, which is also not possible in the current preview? Or at least being able to get the full class name as string from a <reified T>.


#11

+1 on supporting KClass instances as map keys.

Even better would be support for the type-level "is checks" KClass.isSubclassOf and .isSuperclassOf.

A JSON library (or any other serialization library) is a good example. I register a serializer for interface User (using KClass<User>) and I want to serialize all (often hidden) implementations like UserImpl. That should be possible at runtime using the KClass methods mentioned above.


#12

Maybe a flag would do. So that you can have your highly optimized compact version of something and opt in for extensive reflection when you need it.

Also I think reflection is especially usefull when u load code at runtime. In a Microservice architecture for example.

When what is present at runtime could also be determined at compile time there is also always the option to generate some kind of glue at compile time, no?


#13

While it makes sense that the goal of kotlin native is not to compete with a VM, it is problematic if Kotlin Native cannot be competitive with Swift, Go or Rust, all of which do support reflection to some extent without having a VM.

Significantly limits cross platform abilities as well.

Perhaps the goal is less capability that other native languages, offset by cross platform of running same code as JVM… except cannot run the same code as the JVM because do not want to be have similar capabilites as the would be competing with the JVM.

End result is our mobile guys can’t yet join in with moving to Kotlin Native, because Swift can better implement the same code as the andriod app at least conceptually than Kotlin Native can, where a not only can the code not be shared by a new design is needed as well.

Hopefully this will change over time?