Kotlin generic class with embedded instance of parameter - kotlin

class ZabbixAPIResult<T> {
var jsonrpc = ""
var result = T()
var id = ""
}
yields
type parameter T cannot be called as a function
Is it possible to declare something like this in Kotlin? I.e., a class that embeds an instance of a class supplied as a parameter?

Of course you can have a field with type T. But you need to pass either the instance itself or a way to construct it. E.g.
class ZabbixAPIResult<T>(var result: T) {
var jsonrpc = ""
var id = ""
}
or
class ZabbixAPIResult<T>(resultFun: () => T) {
var jsonrpc = ""
var result = resultFun()
var id = ""
}
See https://kotlinlang.org/docs/classes.html#constructors for the details of this syntax.
But Kotlin can't assume T is a class with a default constructor, so your version doesn't work.
(On a side note, it's generally better to avoid using var by default.)

Related

Kotlin get all property value of data class

Is there a syntactic sugar in Kotlin to iterate on each field/property value of a data class?
Sample:
data class User(
var firstName: String = DEFAULT_VALUE_STRING,
var middleName: String = DEFAULT_VALUE_STRING,
var lastName: String = DEFAULT_VALUE_STRING
)
val user = User()
Then check if any of the property's value is empty, considering all of it is String data type with something like this
if (user.properties.any{ it.isBlank() }) {
// TODO ...
}
Probably the closest you'll get is checking all the values of all the generated componentX() functions (since they're only created for the constructor parameter properties, the "data" in a data class) but yeah that involves reflection.
If I were you, I'd create an interface with a properties property and make all your data classes implement that - something like this:
import kotlin.reflect.KProperty0
interface HasStringProperties {
val properties: List<KProperty0<String>>
}
data class User(
var firstName: String = "",
var middleName: String = "",
var lastName: String = ""
) : HasStringProperties {
override val properties = listOf(::firstName, ::middleName, ::lastName)
}
fun main() {
val user = User("Funny", "", "Name")
println(user.properties.any {it.get().isBlank()})
}
So no, it's not automatic - but specifying which properties you want to include is simple, and required if you're going to access it on a particular class, so there's an element of safety there.
Also, because you're explicitly specifying String properties, there's type safety included as well. Your example code is implicitly assuming all properties on your data classes will be Strings (or at least, they're a type with an isBlank() function) which isn't necessarily going to be true. You'd have to write type-checking into your reflection code - if you say "I don't need to, the classes will only have String parameters" then maybe that's true, until it isn't. And then the reflection code has to be written just because you want to add a single age field or whatever.
You don't actually have to use property references in Kotlin either, you could just grab the current values:
interface HasStringProperties {
val properties: List<String>
}
data class User(
var firstName: String = "",
var middleName: String = "",
var lastName: String = ""
) : HasStringProperties {
// getter function creating a new list of current values every time it's accessed
override val properties get() = listOf(firstName, middleName, lastName)
}
fun main() {
val user = User("Funny", "", "Name")
println(user.properties.any {it.isBlank()})
}
It depends whether you want to be able to reference the actual properties on the class itself, or delegate to a getter to fetch the current values.
And of course you could use generics if you want, list all the properties and use filterIsInstance<String> to pull all the strings. And you could put a function in the interface to handle a generic isEmpty check for different types. Put all the "check these properties aren't 'empty'" code in one place, so callers don't need to concern themselves with working that out and what it means for each property

How do I pass data from a variable into a constructor using the body of the variable?

I am trying to assign data to my class using the variable that I created. I want to use the variable as an instance of the membership class. Every time I pass any values I get an error.
error: no value passed for parameter '_number'
var member1 = membership()
error: unresolved reference: _number
member1._number = 1
I am getting this for all properties I try to pass anything to.
I tried to create the class without any constructors but I would still get errors. My goal is to create a list of the variables.
class membership(_number:Int, _name:String, _address:String, _zip:String, _phone:String, _memberSince:String, _memberType:Char)
{
var number: Int = _number;
var name: String = _name;
var address: String = _address;
var zip: String = _zip;
var phone: String = _phone;
var memberSince: String = _memberSince;
var memberType: Char = _memberType;
}
fun main(args: Array<String>) {
var member1 = membership()
member1._number = 1
member1._name = "George Jetson";
member1._address ="123 Main St.";
member1._zip = "99207";
member1._memberSince = "12/01/1997";
member1._memberType = 'L';
}
You have declared the class membership with the primary constructor that expects 7 parameters. Hence, you need to provide values for these parameters when you're instantiating this class:
var member1 = membership(
_number = 1,
_name = "George Jetson",
_address ="123 Main St.",
_zip = "99207",
_memberSince = "12/01/1997",
_memberType = 'L'
)
If you want to create an instance of the class first and then initialize its properties one-by-one, you need it to have a parameterless constructor:
class membership() {
However then you'll have to make all its properties nullable or lateinit because now you cannot provide their initial values upon construction:
class membership() {
var number: Int? = null
var name: String? = null
var address: String? = null
// etc
}
This way you'll be able to initialize them as you want in your question.

Not enough information to infer parameter T

Context: I am building a REST API with kotlin using Spring
Problem: I have a Kotlin class called Response that accepts a generic like this:
class Response<T> {
var data: T? = null
var dataArray: List<T>? = null
var errors: List<String>? = null
get() {
if (field == null) {
this.errors = ArrayList()
}
return field
}
}
When I try to instantiate in one of my API Controllers like this:
val response = Response()
response.setData(someting)
It gives me Not enough information to infer parameter T.
How can I avoid this error?
You will have to specify what T is in this case. Supposing it is a String, you could do it like this:
val response = Response<String>()
response.data = "Something that is a String"

Kotlin Data class copy extension

I am trying to find a solution for a nice kotlin data class solution. I have already this:
data class Object(
var classMember: Boolean,
var otherClassMember: Boolean,
var example: Int = 0) {
fun set(block: Object.() -> kotlin.Unit): Object {
val copiedObject = this.copy()
copiedObject.apply {
block()
}
return copiedObject
}
fun touch(block: Object.() -> kotlin.Unit): Object {
return this.set {
classMember = true
otherClassMember = false
block() }
}
}
val test = Object(true,true,1)
val changedTest = test.touch { example = 2 }
the result of this method is that the changedTest object has classMember = true, otherClassMember = false and example = 2
The problem with this solution is, the class properties are not immutable with var declaration. Does somebody have an idea how to optimize my methods to change var to val?
val says that a variable can't change it's value after initialization at the definition point. Kotlin's generated copy method does not modify an existing copy after construction: this method actually uses retrieved values from an object, replaces these values with ones that provided in copy method (if any), and after that just constructs a new object using these values.
So, it is not possible to perform such an optimization if you are going to change object's state after construction.
If I understood what you want correctly, you can do
data class Object(
val classMember: Boolean,
val otherClassMember: Boolean,
val example: Int = 0) {
fun touch(example: Int = this.example): Object {
return copy(
classMember = true,
otherClassMember = false,
example = example)
}
}
val test = Object(true,true,1)
val changedTest = test.touch(example = 2)
Though you need to repeat parameters other than classMember and otherClassMember but without reflection you can't do better.

Why use this when accessing a private method?

I have a question regarding oop. It might seem really trivial. I have seen example online where they use this to access a private method. Is it really necessary? Is it language specific?
Here is an example which can be done with or withour this.
class A {
def test(): String = {
val x = this.test_2()
x
}
private def test_2(): String = {
"This is working"
}
}
object Main extends App {
val a = new A
val x = a.test
println(x)
}
Here the same code without this. both are working.
class A {
def test(): String = {
val x = test_2()
x
}
private def test_2(): String = {
"This is working"
}
}
object Main extends App {
val a = new A
val x = a.test
println(x)
}
Some languages won't accept the use of a method without the this, like python (self.), but in most case, it's a matter of readability and safety.
If you define a function out of the class with the same name as a method of the class, it can cause a problem.
By adding this, you know it's a method from the class.
The "this" keyword refers to the class which you are currently writing code in it. It is mainly use to distinct between method parameters and class fields.
For example, let's assume you have the following class:
public class Student
{
string name = ""; //Field "name" in class Student
//Constructor of the Student class, takes the name of the Student
//as argument
public Student(string name)
{
//Assign the value of the constructor argument "name" to the field "name"
this.name = name;
//If you'd miss out the "this" here (name = name;) you would just assign the
//constructor argument to itself and the field "name" of the
//Person class would keep its value "".
}
}