Kotlin: Programing is printing kotlin.unit - kotlin

My Kotlin Class will run but it prints out the words: kotlin.Unit. What do I need to change?
fun main(args: Array<String>) {
var myDuck = Duck()
println(myDuck.quack())
}
class Duck() {
fun quack () {
println("Quack, Quack, Quack")
}
}

It is printing that because you are printing the return type of a function that does not return any value. If you are familiar with other languages it is the same as having a void return type.
In kotlin a funtion without a return type returns a unit type, and so when you print the return value of Duck::quack you are printing the string value of a Unit value.
The simplest solution is to not print the return value of Duck::quack; however, if you would like the prinlt to print the return of Duck::quak, it needs to return a useful value. For examle:
class Duck() {
fun quack(): String {
return "Quack, Quack, Quack"
}
}
fun main(args: Array<String>) {
var myDuck = Duck()
println(myDuck.quack())
}
or more idiomatically:
class Duck() {
val quack: String = "Quack, Quack. Quack"
}
fun main(args: Array<String>) {
var myDuck = Duck()
println(myDuck.quack)
}

It's anought to call
myDuck.quack()
wich has already println inside. Calling println(myDuck.quack()) prints type of myDuck.quack because it doesn't return any value.

1.prints "kotlin.Unit" if you don't specify the type
fun main(args: Array<String>) {
var myDuck = Duck()
println(myDuck.quack())
}
class Duck():String {
fun quack () {
return "Quack, Quack, Quack"
}
}

Also as shortly:
fun main() {
println(Duck.quack())
}
class Duck() {
fun quack () = "Quack, Quack, Quack"
}

Related

Is it possible to verify at compile time whether the required function is called for the Factory Class in Kotlin?

class ModelFactory {
fun setA() : ModelFactory {
// blabla...
}
fun setB() : ModelFactory {
// blabla...
}
fun setC() : ModelFactory {
// blabla...
}
fun build() : Model {
// An error occurs if any of setA, setB, and setC is not called.
}
}
//example
fun successTest() {
ModelFactory().setA().setB().setC().build() // No error occurs at compile time
}
fun failTest() {
ModelFactory().setA().build() // An error occurs at compile time because setB and setC are not called.
}
It's awkward grammatically, but I think it's been expressed what I want.
I have already implemented an error-raising runtime for this requirement, but I want to check this at compile time.
If possible, I think I should use annotations. But is this really possible at compile time?
With Kotlin, I have been avoiding builder pattern, as we can always specify default values for non-mandatory fields.
If you still want to use a builder pattern, you can use Step builder pattern that expects all mandatory fields to be set before creating the object. Note that each setter method returns the reference of next setter interface. You can have multiple Step builders based on the combination of mandatory fields.
class Model(val a: String = "", val b: String = "", val c: String = "")
class StepBuilder {
companion object {
fun builder(): AStep = Steps()
}
interface AStep {
fun setA(a: String): BStep
}
interface BStep {
fun setB(b: String): CStep
}
interface CStep {
fun setC(c: String): BuildStep
}
interface BuildStep {
//fun setOptionalField(x: String): BuildStep
fun build(): Model
}
class Steps : AStep, BStep, CStep, BuildStep {
private lateinit var a: String
private lateinit var b: String
private lateinit var c: String
override fun setA(a: String): BStep {
this.a = a
return this
}
override fun setB(b: String): CStep {
this.b = b
return this
}
override fun setC(c: String): BuildStep {
this.c = c
return this
}
override fun build() = Model(a, b , c)
}
}
fun main() {
// cannot build until you call all three setters
val model = StepBuilder.builder().setA("A").setB("B").setC("C").build()
}

How to create an instance of a class by passing the type

I want to be able to say make an instance of this class and give a type then the code can instantiate a new instance of that class.
fun maker(type: Class<Animal>): Animal {
if(type == Class<Dog>) {
return Dog()
}
else if (type == Class<Cat>) {}
...
}
What is a good way to do this?
If they all have zero-argument constructors, you can do:
fun maker(type: Class<Animal>): Animal {
return type.newInstance()
}
You can make it return the type that was passed in for a little more versatility:
fun <T: Animal> maker(type: Class<T>): T {
return type.newInstance()
}
Correct version following your example (not sure if best approach overall):
fun <T: Animal> maker(type: Class<T>): T? {
return when (type) {
Cat::class.java -> Cat() as T
Dog::class.java -> Dog() as T
else -> null
}
}
And then to create objects:
val a = maker(Cat::class.java)
val b = maker(Dog::class.java)
(Updated) I am not an expert in Kotlin but you can do something like this :
import kotlin.reflect.KClass
import kotlin.reflect.full.createInstance
class A {
fun greet() {
println("Hello A");
}
}
class B{
fun greet() {
println("Hello B");
}
}
fun <T : Any> maker(clazz: KClass<T>): T {
return clazz.createInstance();
}
val aObj = maker<A>(A::class);
aObj.greet();
val bObj = maker<B>(B::class);
bObj.greet();
Output:
Hello A
Hello B
I hope now it makes sense you just need to pass the class to the method and it returns an object.
As you will be using Animal as a parent class so you can replace Any => Animal
fun <T : Animal> maker(clazz: KClass<T>): T {
return clazz.createInstance();
}
If the function can be inline you can also use reified type
inline fun<reified T: Animal> make() = T::class.createInstance()
...
val dog = make<Dog>()
Please notice that to use createInstance() the class must have no-arg constructor or IllegalArgumentException will be thrown

How to assign current class instance in Kotlin

I have code which looks something like,
data class X{
fun getSomething(){
var y: Y()
//How can I write this
//this=y.doSomething()
}
}
class Y{
fun doSomething(): X{
//...
return x }
}
I want to assign this to an object that I am returning from some other method in some other class.
You cannot assign anything to this and also, data classes should be immutable. Just reassign your reference:
data class X(val x: String) {
fun getSomething() = Y().doSomething()
}
class Y {
fun doSomething(): X {
return X("fromY")
}
}
fun main(args: Array<String>) {
val second = X("first").getSomething()
}

Is possible to change dynamically method for an instance?

I wrote down this code:
open class Test(){
override fun toString(): String {
return "This is test!"
}
}
fun createTestX(): Test {
return object : Test() {
override fun toString(): String {
return super.toString() + "XXX"
}
}
}
fun main(args: Array<String>) {
val x = createTestX()
println(x)
}
It works as expected but I am curious whether is it possible to change method of instance using for example lambda like this:
val x = Test()
x.toString = () -> x.toString() + "XXX"
What you can do
class C {
var example:()->String = this::toString
}
fun main(args: Array<String>) {
val c = C()
println(c.example())
c.example = {"ABCDEF"}
println(c.example())
}
Limitations
Although this works for swapping fields, you cannot use it to override methods. This can be worked around by defining the method to invoke the field.
class C {
var example:()->String = {"ABC"}
override fun toString() = example()
}
fun main(args: Array<String>) {
val c = C()
println(c)
c.example = {"DEF"}
println(c)
}
Output:
ABC
DEF

How to get names and values of method's parameters?

Is there possibility to get names of method's parameters inside method code? Can anyone show example of it?
I found only this solution at this time, but dislike it..:
class Greeter() {
fun greet(name: String) {
val c = Greeter::class;
for (m in c.memberFunctions) {
if (m.name == "greet") {
val p = m.parameters
println(p.toString())
}
}
println("Hello, ${name}");
}
}
fun main(args: Array<String>) {
Greeter().greet("UserName")
}
update: i found another solution, but now i have one more question:
How to get pairs of ParamName, ParamValue at function greet?
class Greeter() {
fun greet(name: String) {
val p = Greeter::greet.parameters
println(p.toString())
println("Hello, ${name}");
}
}
fun main(args: Array<String>) {
Greeter().greet("UserName")
}
Parameter names are available through the KParameter.name property:
class Greeter() {
fun greet(name: String) {
val p = Greeter::greet.parameters
println("Hello, ${p[0].name}")
}
}
Parameter values, on the other hand, cannot be obtained reflectively easily on JVM.