Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 1079 Vote(s) - 3.41 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Why is a generic typed property nullable?

#1
I am trying to create a parameterized class with a `lateinit` non-nullable property of the generic type:

class Test<T> {

private lateinit var t : T

private lateinit var s : String

}

The latter is allowed, but the former is not. The compiler returns the following error:

> Error:(7, 11) ''lateinit'' modifier is not allowed on nullable properties

Since I didn't declare `T?`, I am confused as to why this is the case.
Reply

#2
T, when used as a type parameter, is always null. (All type parameters are nullable). You don't need to declare `T?`, only `T` is needed. To use declare an upper bound, do this `public class Foo<T: Any>` (`Any` isn't nullable)
Reply

#3
[Kotlin In Action][1] has following to say on nullability of type parameters

> Nullability of type parameters:
>
> By default, all type parameters of
> functions and classes in Kotlin are nullable. Any type, including a
> nullable type, can be substituted for a type parameter; in this case,
> declarations using the type parameter as a type are allowed to be
> null, even though the type parameter T doesn’t end with a question
> mark.

How to make type parameters not-null?

> To make the type parameter non-null, you need to specify a non-null
> upper bound for it. That will reject a nullable value as an argument.
>
> Note that type parameters are the only exception to the rule that a
> question mark at the end is required to mark a type as nullable, and
> types without a question mark are non-null. The next section shows
> another special case of nullability: types that come from the Java
> code.

[1]:

[To see links please register here]

Reply

#4
> The default upper bound (if none specified) is `Any?` ([Source][1])

In other words, when you use `T`, Kotlin assumes that this might be _any_ type, be it primitive, object or a nullable reference.

To fix this add an upper type:

class Test<T: Any> { ... }


[1]:

[To see links please register here]

Reply

#5
Nullable Type Parameter
-----------------------
`Any?` is the supertype of *all* types in Kotlin. So, when you don't specify any upper bound for the type parameter `T`, the default bound is `Any?`.

For example:

`class Test<T> { }`

is the same as

`class Test<T : Any?> { }`

This results in the `T` being nullable in the following example:

class Test<T> {
private var t : T // T can have a nullable type
}

This means that the generic type above can be instantiated with nullable as well as non-null type arguments:

val test: Test<Int> = Test() // OK
val test: Test<Int?> = Test() // OK

----------


Non-null Type Parameter
-----------------------
`Any` is the supertype of *all non-null* types in Kotlin. So, to make a generic class accept only non-null type arguments, you need to explicitly specify `Any` as an upper bound of `T`, that is `T : Any`.

This results in the `T` being non-null in the following example:

class Test<T : Any> {
private var t: T // T is non-null
private var t2: T? // T can be used as nullable
}

The generic type with `T : Any` can be instantiated only with non-null type arguments and prevents the instantiation with nullable type arguments:

val test: Test<Int> = Test() // OK
val test: Test<Int?> = Test() // Error

----------

`lateinit var`
----------------

The `lateinit var` must always be non-null because it is used in the cases where you want a variable to be non-null but don't want to initialize its value at the time of object creation.

So, to create the `lateinit` variable that has the same type as the type parameter `T`, the type parameter needs to be non-null too.

To achieve that, specify the upper bound `T : Any` explicitly:

class Test<T : Any> {
private lateinit var t: T
}

It's worth noting that you can use a more specific type, if you have one depending on your business logic. For example, instead of `T : Any`, you could have `T : SomeProduct`, if that is what you want the upper bound to be. It just needs to be non-null.

This will ensure that the user of your class won't be able to instantiate with nullable type arguments and your assumption of the `lateinit var` always being non-null will hold true.

----------
That's it! Hope that helps.
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through