Make Java class literal easy ... or ... I'd rather not have Foo::class.java for the next 10 years


#1

Hi,

I really see Kotlin as very likely to be my preferred jvm language for the next 10 years (with the virtually seemless java interop the key).

For me, I’m seeing Foo::class.java pop up enough times for me to think ‘gee it would be nice if that was more clean / seemless’.  I am seeing this in dependency injection a lot but you get the odd time class literals are used to support generics (and yes sometimes you can use the subclass trick there to avoid needing to pass the class literal).  I’m not expected (nor asking for) reified generics so in that sense I see the java class literal being used in these cases for some time.

Ideally I’d just like to see a more succinct syntax that ideally didn’t require kotlin-reflect.

If simplier java class literals is possible and deemed a good idea some syntax thoughts are:

  • Foo::jclass   … ::jclass, I’d be happy with this


    - Foo::klass and Foo::class   … for kotlin class and java class respectively.  Changing kotlin class from ::class to ::klass would require migration

  • Foo   … groovy style, probably not a good idea

Cheers, Rob.


#2

We're sort of settled on "Foo::class.java" for now. There are some issues currently, which are heavily discussed at the moment. For example as you mentioned it currently requires kotlin-reflect.jar -- we have a solution and reflection implementation won't be needed eventually.

Re your proposals: the first and the second clash syntactically with callable references (you can have a function/property named ‘jclass’ or ‘klass’), and the third one is used to obtain the value of the companion object.

Would you mind sharing what exactly don’t you like about “Foo::class.java”? Thanks!


#3

> what exactly don't you like about "Foo::class.java"?

Verbosity (so yes, I’m being picky).  I also think it is more intuitive to be able to use Foo::jclass.

Once the need for kotlin-reflect is removed then that will help people who don’t know about that but for me that is not such a problem (being mostly server side currently so an extra dependency is no problem).

In terms of verbosity, put enough ::class.java all together in a dependency injection module it just looks ‘more verbose than it should be’.  So yes, I’m being ‘picky’ but I wanted to raise the issue because to me it also suggested that java class literal was more a ‘second class citizen’ compared to kotlin ::class and for me my usage will be 99% java class literal and 1% kotlin class / kotlin reflection. I don’t think that is too much of an exaggeration - java class literal is way way more important to me than kotlin class / kotlin reflection.

> you can have a function/property named ‘jclass’

Yes, but people can migrate if we ask them nicely enough :slight_smile: … seriously ::jclass seems to me intuitive and more what I’d expect (::class and ::jclass would have equal standing).  Personally I an hoping that enough people have similar thoughts and that it is early enough that anyone currently using ‘::jclass’ could migrate.

If you don’t ask …  (well, I’d probably spend the next 10 years regretting not asking)

Cheers, Rob.


#4

Let me be more clear: migration of existing code is not an issue. The issue is that to allow "Foo::jclass" as you ask, we'd have to introduce a new keyword "jclass" to the language. This means that the language will syntactically be bound to the specific platform. Up to this moment we're still trying not to allow this to happen, so we need to carefully evaluate the costs and benefits of this proposal.

I agree something like “::jclass” would be more convenient than “::class.java” in your case, but maybe we can come up with a platform-independent, preferably library-based, approach.


#5

> The issue is that to allow "Foo::jclass" as you ask, we'd have to introduce a new keyword "jclass" to the language. This means that the language will syntactically be bound to the specific platform.

Right. So perhaps a keyword that is more platform agnostic … “Foo::nclass” … where n is short for “native” etc.  My ‘just throwing this out there’ thought on that is … the 2 platforms I think of are ‘java/jvm’ and ‘javascript’ so maybe “jclass” is actually a good choice :slight_smile: … more intuitive for the jvm and javascript platforms and perhaps those are the most important 2 platforms?

> syntactically be bound to the specific platform

So another way of thinking about my issue is that the platform class ‘java class literal’ is vastly more important to me than KClass and the jvm + andriod platform is hugely important to me … so yes, I’m going to be hoping the idea of a “::jclass” or equivalent to easily expose the ‘native platform class’ gets some traction.

Cheers, Rob.


#6

Maybe interesting from a javascript perspective - it looks like you can just use Foo for dependency injection in ES6.  That is, no need for Foo.class etc with dependency injection via ES6 / Angular 2.0 style in the link below.

Caveat: I have not used ES6 or Angular 2.0 etc yet so I’m not up with the play on where this is at or going with Javascript / ES6 but … it does look like you don’t need a separate ‘native plaform class’ to perform dependency injection in javascript / ES6.

That is, assuming that the link below is accurate you can juse use Foo (no need for Foo.class etc).
http://blog.thoughtram.io/angular/2015/05/18/dependency-injection-in-angular-2.html

Cheers, Rob.


#7

>Maybe interesting from a javascript perspective - it looks like you can just use Foo for dependency injection in ES6.

In Groovy the same, if I understand correctly. String is equivalent to String.class.

println String // outputs “class java.lang.String”


#8

>That is, assuming that the link below is accurate you can juse use Foo (no need for Foo.class etc). >thoughtram

I was there, when Pascal held this talk in Hannover. :smiley: He, didn’t explicitely state it, but Foo is actually a reference to a function. The “class” keyword in ES6 basically allows shorter syntax for functions.

class Foo {}

is roughly equivalent to

var Foo = (function () {

  function Foo() {}

  return Foo;

})();

Example:
https://babeljs.io/repl/#?experimental=false&evaluate=false&loose=true&spec=false&code=class%20Foo%20{%0A%20%20Foo%28%29%20{}%0A}%0A

Edit: Linkfix.


#9

Thanks!!


#10

You're welcome.

So basically if you have

var Foo = function() {}

then you can call it as a function

Foo();

or you can call it as a function, but also change the meaning of “this” within the function

new Foo();

The function name starts with a uppercase letter. This is purely a convention to indicate, that this function has to be used with the “new” keyword.

In JavaScript a function is an object and has something like fields (they are called properties in JavaScript). By convention, if you want to add “instance methods” to the “class function” you use a trick to encapsulate the scope within the function:

(function() {

  // code

})();


#11

It could also help if we simply could use the reified annotation just like with the `javaClass<T>()` function. Then we can hide the verbosity behind a function: e.g.:

fun main(args: Array<String>) {   register<Foo, Bar>() }

interface Foo
class Bar : Foo

inline fun <reified T:Any, reified C : T> register() {
  println("type = {javaClass&lt;T&gt;()}, concrete = {javaClass<C>()} ") //works
  println("type = {T::class.java}, concrete = {C::class.java} ") // doesn’t compile
}


#12

>> > what exactly don't you like about "Foo::class.java"? > Verbosity

FYI Another use case … class literal as the key for maps.  e.g.

// return the cache for a given type …
cacheManager.get(Country::class.javaClass);


#13

Er, looks like Country.javaClass works in this case ... I better go back and check.

// .javaClass works here …
cacheManager.get(Country.javaClass);