What is the use of constructor() and what does it do? - kotlin

I'm studying object oriented programming using Kotlin at the moment (I'm fairly new to it) and I came across this code:
class Human{
var name:String = "Joe"
var id:String = "123.123.123-12"
constructor()
fun humanInfo() = "$name and $id"
}
fun main() {
val joe = Human()
println(joe.humanInfo())
}
I found out that there are primary and secondary constructors in Kotlin, but I didn't really understand what they are and what they do. What is the use of constructor() function here? And is it a primary constructor?

Related

Calling method without creating an instance

I want to call a function in the 'static' way
i heard there isn't an equivalent for static in Kotlin
so I'm looking into a way to make it work.
fun main() {
var ob1 : Ob1 = Ob1()
ob1.try1()
}
class Ob1{
fun try1() = println("try 1S")
}
If I use java i would just name it static than call the function directly.
Thanks on advance..
You can define function outside class or simply define it in a companion object:
class Ob1{
companion object{
fun try1() = println("try 1S")
}
}
fun main() {
Ob1.try1()
}
Yo can read more in official documentation

foreach a list of class constructors in kotlin

I'm pretty new to kotlin and I've been reading through the language docs to start picking it up.
I learn much better when I type out the examples, so I wanted to make a little example running codebase so I could follow along with the examples.
This is fine for writing each of examples in the main.kt file on it's own, running it, then blowing it away, but I'd like to create an example class for each section, create a list of the classes in main, and then foreach over them.
I created an interface which has a declaration for a common member function for running the examples:
interface ExampleCodeInterface {
/**
* Run the examples for the current Example class
*/
fun runExamples()
}
And defined an example class:
class CollectionExamples : ExampleCodeInterface{
fun listExample() {
val systemUsers: MutableList<Int> = mutableListOf(1,2,3)
val sudoers: List<Int> = systemUsers
fun addSudoer(newUser: Int) {
systemUsers.add(newUser)
}
fun getSysSudoers(): List<Int> {
return sudoers
}
addSudoer(4)
println("Total sudoers: ${getSysSudoers().size}")
getSysSudoers().forEach {
i -> println("Some useful info on user $i")
}
}
override fun runExamples() {
listExample()
}
}
The thing I'm not sure on is how to properly run this from main.kt
I know the class works because when I create a new instance and fire the method it works, but I can't quite figure out how to properly create a list of class constructors so that I can have a list of classes that all extend the ExampleCodeInterface that I can forEach through and fire the method:
fun main(args: Array<String>) {
val exampleClassList: List<ExampleCodeInterface> = listOf<ExampleCodeInterface>(CollectionExamples)
exampleClassList.forEach {
val exampleSet = it()
exampleSet.runExamples()
}
// val collectionExamples = CollectionExamples()
// collectionExamples.runExamples()
}
I've been trying to piece together the logic from the docs, but I think there are some details that I don't know yet.
Any help is appreciated!!

Pass different generic types to function

I have a function in Kotlin that can take a generic object as a parameter. The two objects are unrelated and do not share any base types. They both however implement the same functions. I would like to re-use those functions within my function. Something along these lines:
fun storeUser(datastore: Any) {
datastore.storeName("John")
}
// Call the function
val datastore1 = DataStore1()
storeUser(datastore1)
val datastore2 = DataStore2()
storeUser(datastore2)
Both the DataStore1 and DataStore2 have a function called "storeName". Is there a way in Kotlin to re-use this function in the storeUser function? I tried playing around with Generics but this does not seem possible.
The example code above is simple. In my real app, there are many more functions beside storeName. If I can't have a common function to store my data, I will need to create two separate functions and duplicate the storage for both. That kind of sucks.
I recommend using a common interface for both classes. If they are provided by a thid-party library, you could wrap them in your own classes and interface.
If you don't want to do that, you could just check the type of the parameter in the storeUser function:
fun storeUser(datastore: Any) {
when(datastore) {
is DataStore1 -> datastore.storeName("John")
is DataStore2 -> datastore.storeName("John")
else -> throw IllegalArgumentException()
}
}
But note that if you have another datastore in the future, you will need to add one more is clause to this function. That makes this code not very maintainable...
Better solution
If you create an interface Datastore:
interface Datastore {
fun storeName(name: String)
}
and the make your datastores implement it:
class Datastore1 : Datastore {
//Datastore1.storeName implementation
}
class Datastore2 : Datastore {
//Datastore2.storeName implementation
}
Then, you don't need to check the types in storeUser function. Just change its parameter type to Datastore:
fun storeUser(datastore: Datastore) {
datastore.storeName("John")
}
If Datastore1 and Datastore2 are provided by a third-party library, you can wrap them in your own classes and implement your Datastore interface:
class FirstDatastore : Datastore {
private val datastore = DataStore1()
override fun storeName(name: String) {
datastore.storeName(name)
}
}
class SecondDatastore : Datastore {
private val datastore = DataStore2()
override fun storeName(name: String) {
datastore.storeName(name)
}
}
So you can call your function using your classes:
val datastore1 = FirstDatastore()
storeUser(datastore1)
val datastore2 = SecondDatastore()
storeUser(datastore2)
As I said in the comment to the question, it would really be better to write a common interface for these classes. If that's not possible because the classes come from an external dependency, the second best thing to do would be to wrap the code as Héctor did.
Kotlin is a statically typed language, so unfortunately wrapping code like this results in a lot of duplication. If you didn't want to write a new wrapper for every new instance of the DataStore, you could use reflection to call it dynamically. This way you only have to write the definition once. However, you forego all the compile-time benefits of static checks, so it's not really a good idea. It was good to do as an exercise though. 😎
class WrappedDataStore<T : Any>(private val dataStore: T) {
private fun callDynamically(methodName: String, vararg args: Any?) {
val argTypes = args.map { it?.let { it::class.java} }.toTypedArray()
dataStore.javaClass
.getMethod(methodName, *argTypes)
.invoke(dataStore, *args)
}
fun storeName(name: String) = callDynamically("storeName", name)
}
fun <T : Any> storeUser(dataStore: WrappedDataStore<T>) =
dataStore.storeName("John")
fun main() {
val one = WrappedDataStore(DataStore1())
val two = WrappedDataStore(DataStore2())
one.storeName("foo")
two.storeName("bar")
storeUser(one)
storeUser(two)
}
class DataStore1 {
fun storeName(foo: String) = println("DataStore1 $foo")
}
class DataStore2 {
fun storeName(bar: String) = println("DataStore2 $bar")
}
Output:
DataStore1 foo
DataStore2 bar
DataStore1 John
DataStore2 John

Kotlin primary and secondary constructors during inheritance

I am learning Kotlin and I'm kind of stuck with the constructors. I've written a program to help me understand the concept. The program is as follows:
open class Animal(){
var name :String = "noname";
constructor(name:String):this(){
this.name = name
}
open fun eat(){
println("$name the animal is eating")
}
}
class Dog: Animal{
constructor():super()
constructor(name : String):super(name)
override fun eat(){
println("$name the dog is eating")
}
}
fun main (args:Array<String>){
var a1 = Animal("foo")
var a2 = Animal()
var d1 = Dog("bar")
var d2 = Dog()
a1.eat()
a2.eat()
d1.eat()
d2.eat()
}
Is it possible to modify the program so that the child class calls the parent's primary constructor without using another secondary constructor.
What I'm trying to achieve here is to not force the user to pass a parameter while creating objects using primary and secondary constructors.
Please forgive me if my question is dumb. I am novice here.
In Kotlin, you can set the default value in the constructor itself:
open class Animal(var name: String = "noname"){
open fun eat(){
println("$name the animal is eating")
}
}
class Dog(name: String = "noname"): Animal(name){
override fun eat(){
println("$name the dog is eating")
}
}
This way, "noname" is assigned if no string is provided when invoking the constructor. Also, when you create a Dog object, it will always call the parent constructor.

How can I set the JsName for a property's backing field in Kotlin?

I played about with Kotlin's unsupported JavaScript backend in 1.0.x and am now trying to migrate my toy project to 1.1.x. It's the barest bones of a single-page web app interfacing with PouchDB. To add data to PouchDB you need JavaScript objects with specific properties _id and _rev. They also need to not have any other properties beginning with _ because they're reserved by PouchDB.
Now, if I create a class like this, I can send instances to PouchDB.
class PouchDoc(
var _id: String
) {
var _rev: String? = null
}
However, if I do anything to make the properties virtual -- have them override an interface, or make the class open and create a subclass which overrides them -- the _id field name becomes mangled to something like _id_mmz446$_0 and so PouchDB rejects the object. If I apply #JsName("_id") to the property, that only affects the generated getter and setter -- it still leaves the backing field with a mangled name.
Also, for any virtual properties whose names don't begin with _, PouchDB will accept the object but it only stores the backing fields with their mangled names, not the nicely-named properties.
For now I can work around things by making them not virtual, I think. But I was thinking of sharing interfaces between PouchDoc and non-PouchDoc classes in Kotlin, and it seems I can't do that.
Any idea how I could make this work, or does it need a Kotlin language change?
I think your problem should be covered by https://youtrack.jetbrains.com/issue/KT-8127
Also, I've created some other related issues:
https://youtrack.jetbrains.com/issue/KT-17682
https://youtrack.jetbrains.com/issue/KT-17683
And right now You can use one of next solutions, IMO third is most lightweight.
interface PouchDoc1 {
var id: String
var _id: String
get() = id
set(v) { id = v}
var rev: String?
var _rev: String?
get() = rev
set(v) { rev = v}
}
class Impl1 : PouchDoc1 {
override var id = "id0"
override var rev: String? = "rev0"
}
interface PouchDoc2 {
var id: String
get() = this.asDynamic()["_id"]
set(v) { this.asDynamic()["_id"] = v}
var rev: String?
get() = this.asDynamic()["_rev"]
set(v) { this.asDynamic()["_rev"] = v}
}
class Impl2 : PouchDoc2 {
init {
id = "id1"
rev = "rev1"
}
}
external interface PouchDoc3 { // marker interface
}
var PouchDoc3.id: String
get() = this.asDynamic()["_id"]
set(v) { this.asDynamic()["_id"] = v}
var PouchDoc3.rev: String?
get() = this.asDynamic()["_rev"]
set(v) { this.asDynamic()["_rev"] = v}
class Impl3 : PouchDoc3 {
init {
id = "id1"
rev = "rev1"
}
}
fun keys(a: Any) = js("Object").getOwnPropertyNames(a)
fun printKeys(a: Any) {
println(a::class.simpleName)
println(" instance keys: " + keys(a).toString())
println("__proto__ keys: " + keys(a.asDynamic().__proto__).toString())
println()
}
fun main(args: Array<String>) {
printKeys(Impl1())
printKeys(Impl2())
printKeys(Impl3())
}
I got a good answer from one of the JetBrains guys, Alexey Andreev, over on the JetBrains forum at https://discuss.kotlinlang.org/t/controlling-the-jsname-of-fields-for-pouchdb-interop/2531/. Before I describe that, I'll mention a further failed attempt at refining #bashor's answer.
Property delegates
I thought that #bashor's answer was crying out to use property delegates but I couldn't get that to work without infinite recursion.
class JSMapDelegate<T>(
val jsobject: dynamic
) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
return jsobject[property.name]
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
jsobject[property.name] = value
}
}
external interface PouchDoc4 {
var _id: String
var _rev: String
}
class Impl4() : PouchDoc4 {
override var _id: String by JSMapDelegate<String>(this)
override var _rev: String by JSMapDelegate<String>(this)
constructor(_id: String) : this() {
this._id = _id
}
}
The call within the delegate to jsobject[property.name] = value calls the set function for the property, which calls the delegate again ...
(Also, it turns out you can't put a delegate on a property in an interface, even though you can define a getter/setter pair which work just like a delegate, as #bashor's PouchDoc2 example shows.)
Using an external class
Alexey's answer on the Kotlin forums basically says, "You're mixing the business (with behaviour) and persistence (data only) layers: the right answer would be to explicitly serialise to/from JS but we don't provide that yet; as a workaround, use an external class." The point, I think, is that external classes don't turn into JavaScript which defines property getters/setters, because Kotlin doesn't let you define behaviour for external classes. Given that steer, I got the following to work, which does what I want.
external interface PouchDoc5 {
var _id: String
var _rev: String
}
external class Impl5 : PouchDoc5 {
override var _id: String
override var _rev: String
}
fun <T> create(): T = js("{ return {}; }")
fun Impl5(_id: String): Impl5 {
return create<Impl5>().apply {
this._id = _id
}
}
The output of keys for this is
null
instance keys: _id
__proto__ keys: toSource,toString,toLocaleString,valueOf,watch,unwatch,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,__defineGetter__,__defineSetter__,__lookupGetter__,__lookupSetter__,__proto__,constructor
Creating external classes
Three notes about creating instances of external classes. First, Alexey said to write
fun <T> create(): T = js("{}")
but for me (with Kotlin 1.1) that turns into
function jsobject() {
}
whose return value is undefined. I think this might be a bug, because the official doc recommends the shorter form, too.
Second, you can't do this
fun Impl5(_id: String): Impl5 {
return (js("{}") as Impl5).apply {
this._id = _id
}
}
because that explicitly inserts a type-check for Impl5, which throws ReferenceError: Impl5 is not defined (in Firefox, at least). The generic function approach skips the type-check. I'm guessing that's not a bug, since Alexey recommended it, but it seems odd, so I'll ask him.
Lastly, you can mark create as inline, though you'll need to suppress a warning :-)