4
votes

Kotlin does not allow this:

private lateinit var port: Int;

What can I use to mark an integer like value as allow to lateinit?

I understand why this does not work (Int is primitive), I need to know what to use instead?

Edit 1

It's not a duplicate of this because I want to know what to use in this case, not why it's happening: Why doesn't Kotlin allow to use lateinit with primitive types?

Edit 2 As suggested by @Roland below - BitInteger works for me:

private lateinit var port: BigInteger;

I'm justing using it to generate a URL so I really only need it in a String concatenation.

3
Hm, what a seemingly arbitrary limitation. As if Int? was disallowed. - EpicPandaForce
You can't lateinit nullable types, so Int? does not work. - mikeb
@marstran - Not a duplicate, I specifically said that I understand why it does not work, and that question answers that nicely. I want to know what to do instead. - mikeb
you could wrap it, if you really want to keep Int and do not want a default value... or use some other type, e.g. BigInteger? ;-) - Roland

3 Answers

4
votes

Some variants come to my mind, but depending on how you use it later on, none might be suitable to you.

  1. just use a default value, e.g.:

    var port : Int = 8080
    
  2. use some other Number-type instead of Int, e.g.

    class Server {
      lateinit var port : Number
    }
    

    You can then call port.toInt() if you need to. But: there are a lot of Number-types, so narrowing it down to e.g. BigInteger might make sense. Otherwise you might get objects, you do not want to accept in the first place.

  3. using Delegates.notNull

    var port : Int by Delegates.notNull()
    

    but: even though you spare your null-value then, you can't check whether the variable has been initialized, so you just have to deal with an exception as soon as you want to access it... not very nice I think... but if you are sure you get a value, then that might be ok for you too.

  4. just use Int? and skip the lateinit, e.g.:

    class Server {
      var port : Int? = null
    }
    

    Instead of ::port.isInitialized you would ask for port != null, but: you need to handle the possible null-value now, but with ? that shouldn't be such a big problem.

  5. use Int? with Delegates.vetoable in case you do not want to accept null-values after you got your first value, making it basically something like lateinit ;-)

    class Server {
      var port : Int? by Delegates.vetoable(null as Int?) {
        _, _, newValue -> newValue != null
      }
    }
    

    and check again using port != null, which now behaves similar to ::port.isInitialized

Not that I am a big fan of the last two as they introduce null again, but depending on what you do, that might be perfectly ok...

As you added something regarding String concatenation, I would even more so use Int? here. You can then still use something like:

url = "$host${port?.let { ":$it" }?:""}"
// or:
url = port?.let { "$host:$it" } ?: host
// or
url = listOfNotNull(host, port).joinToString(":")

The same can't be really easier with the ::port.isInitialized?

1
votes

i don't know the perfect solution you are looking for, but i do it like this (in case you are actually forced to use a primitive type):

 class Example{
    private var _port: Int? = null

    var port:Int
         get() = this._port!!
         set(i) { _port = i }
    }

At least this allows you to use the property as if was not nullable. Best solution we found for us so far!

0
votes

If your project is not cross-platform, the obvious solution would be

@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") lateinit var i: java.lang.Integer

which has one-to-one correspondence with Int values (unlike BigInteger).