Showing posts with label Kotlin. Show all posts
Showing posts with label Kotlin. Show all posts

Sunday, 1 August 2021

Android Java to Kotlin migration by example part 13: operator overloading

This time again we're going to be talking about something available in Kotlin, but not in Java: operator overloading.

Operator overloading means that we can apply operators, like + (someobject+anotherone) or [ ] (someobject[5]) to our objects. Expression like this (someobject + anotherone) can be thought of as methods: it's just another way of expressing someobject.plus(anotherone)someobject[5] would mean "call the method [] with parameter 5 on someobject.  

Altough operator overloading is an old concept (it's common in C++, where - for example - the famous cout<<"Something"; actually uses overloaded left bit shift operator for object cout of class ostream; it's also available in C# and Python), it's not implemented in Java (which was a deliberate choice of its creators).

Still, it can be very useful and Kotlin allows it.

Let's get to our code. I think the most basic example of operator overloading is use of class representing complex numbers (the code below is the full program, with both class definition and it's use):

package com.mypackage

import kotlin.Exception
import kotlin.math.sqrt

class Complex(var re: Float, var im: Float){

fun modulus(): Float{ // just a method
return sqrt(re*re+im*im)
}

// "this" can be omitted
operator fun plus(another: Complex): Complex{ // a+b
return Complex(this.re+another.re,this.im+another.im)
}

operator fun minus(another: Complex): Complex{ // a - b
return Complex(re-another.re, im-another.im)
}

operator fun times(another: Complex): Complex{
var resultRe = re*another.re-im*another.im
var resultIm = re*another.im+im*another.re
return Complex(resultRe, resultIm)
}

operator fun compareTo(another: Complex): Int{ // == > < <= >=
if(this.modulus()<another.modulus())
return -1
if(this.modulus()>another.modulus())
return 1
return 0
}

operator fun get(arg: Int): Float{ // someComplex[0]
if(arg==0)
return this.re
if(arg==1)
return this.im
throw IllegalArgumentException()

}

override fun equals(other: Any?): Boolean {
if(other is Complex)
return (this.re==other.re && this.im == other.im)
else
throw Exception("wrong class")
}

override fun toString(): String{
return "($re,$im)"
}

}

fun main() {
val c = Complex(1.0f,0.0f)
val c2 = Complex(1.0f, 0.0f)
val c3 = Complex(10.0f,10.0f)
val sum = c+c2

val sum2 = c.plus(c2)

val someMul = Complex(10.0f,5.0f)* Complex(7.0f,-2.0f)

println("multiplied:$someMul")

println(sum)
println(sum2)
println(sum[0])
println(c3>c2)

println(c==c2)
}

... which defines the class Complex representing a complex number, and overloads the infix "+", "-", "*", comparison (<, >, >=, <=) and [ ] operators. There is also modulus function, which is just a method... And which we use to define our overloaded comparison operators behaviour (operator fun compareTo).

The execution of the code above results in the following output:

multiplied:(80.0,15.0)
(2.0,0.0)
(2.0,0.0)
2.0
true
true

We can see that my implementation of complex multiplication is correct ;)

The +, -, * operators, implemented as plus,  minus, and times are quite self-explanatory: they take one parameter, and use this.re and this.im (or just re and im) of current (left to operand) values to compute the results, which they return. 

In order to override them, we use operator keyword before a method definition. Please note they can be called both as operators ( val sum = c+c2 ) or just as methods ( val sum2 = c.plus(c2)).

In comparison operator overload (operator fun compareTo(another: Complex)) I've used previously defined modulus method, because there is no unequivocal way of comparing complex numbers - so I compare their moduli. This operator should return -1 if the first operand is "smaller" than second one (in our case it's modulus is smaller), 1 if it's "bigger" and and 0 it they're the same.

I've also overloaded get operator, which affects suqare brackets, like in the call println(sum[0]). What it does, is simply return real part of our complex as 0-th element and the imaginary part as 1-st one. If called with something else than 0 or 1, it would throw IllegalArgumentException(). Typically this operator would be used for some class representing collection (like list - please note in Java you'd have to use somelist.get(i) instead of just somelist[i] to get i-th element of the somelist List or like text string, where it would return n-th character).

There are other operators to overload, like not (!) - but I simply can think of no use of it regarding complex numbers :). When you type operator fun  (with the spacebar after the word fun) and hit Ctrl+Space in IntelliJ Idea or Android Studio, you'll get the full list of the operators possible to overload with their symbols on the right and corresponding keywords (like plus or minus in the example above) on the left:



Please note compareTo does not affect == comparison effect: that's what overriden function override fun equals(other: Any?) does.

A word on Java - of course, lack of operator overloading in Java doesn't mean we could not implement a class Complex in this language. We can, of course. But the only way of representing "sum of complex1 and complex2" would be some function or method, like complex1.add(complex2) or maybe sum(complex1, complex2) - not the intuitive and obvious Kotlin's complex1+complex2.

Well, that would be basics. More details, including the full list of operators available for overloading in Kotlin are available in the Kotlin's documentation.


Saturday, 31 July 2021

Android Java to Kotlin migration by example part 12: a few Kotlin features

Today I'm not going to use the format typical for this series, instead - I'll just show you two features of Kotlin I've just learned about. As there are no named arguments and default parameter values in Java, I cannot provide you the Java code counterpart this time :)

Kotlin functions have named arguments, actually exactly as in Python.

What that means (assuming you haven't read the previous post?). Well, let's consider the following code:

package com.mypackage

fun divide(nominator: Float, denominator: Float): Float{
return nominator/denominator
}
fun main() {

val result = divide(10.0f,5.0f)
val result2 = divide(nominator = 10.0f, denominator = 5.0f)
val result3 = divide (denominator = 5.0f, nominator = 10.0f)

println(result)
println(result2)
println(result3)
}

It produces the following result:

2.0 2.0 2.0

The function divide has (quite obviously) two arguments: nominator and denominator. If you call the function without specifying their names, their order matters: in our case, the first argument is divided by second one.

But... You can also call our function with named parameters: as in Python, here also it means you can switch their order (the calls initializing result2 and result3.

And second thing: also exactly as in Python, the parameters in Kotlin can have default values.

So that the following code, for example:

fun power(base: Float, exponent: Float = 2.0f): Float{
return base.pow(exponent)
}
fun main() {

val a2cubed = power(10f,3f)
var a2squared = power(10f)

println(a2cubed)
println(a2squared)
}

... makes power function actually a square function, when called with just one argument.

The code above produces the following result:

1000.0
100.0

I think that's all for today. Both named parameters and default values are neat features - especially in functional language - and another advantage of Kotlin over Java - it's good to know they're available.

Sunday, 18 July 2021

Android Java to Kotlin migration by example part 11: basic exceptions

Today I'll show you how to catch and throw an exception in Kotlin.

The program illustrating the problem will be simple code, doing integer division. Such division throws an ArithemeticException if the divider is 0

Traditionally, let's begin with Java:

Listing 1 (Java)

import static java.lang.System.out;

public class MainClass {

static int divide(int a, int b) {
return a / b;
}

public static void main(String[] args) {
out.println("" + divide(6, 2));

try{
out.println(""+divide(3,0));
}catch(ArithmeticException ae){
out.println("division by 0!");
}
out.println("" + divide(3, 0));

}
}

We call our divide method 3 times: with (6,3) arguments (which simply gives us result: 2), with (3,0) arguments inside the try...catch block (which results in catching the exception and printing division by 0! to console, and finally with (3,0) arguments without try...catch block, which results in end of program execution, with message:

Listing 2 (result)

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at MainClass.divide(MainClass.java:6)
    at MainClass.main(MainClass.java:17)

So the program prints altogether:

Listing 3 (result)

3
division by 0!
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at MainClass.divide(MainClass.java:6)
    at MainClass.main(MainClass.java:17)

First, the result is simply computed. Then, as integer division by 0 is not possible, the program throws the ArithmeticException exception. The program continues, because we catch it. Then, the program throws it again, and - as it's not caught this time, the program execution ends.

The Kotlin version of program from Listing 1 is pretty straightforward:

Listing 4 (Kotlin)

package com.mypackage

import java.lang.ArithmeticException

fun divide(a: Int, b: Int): Int{
return a/b
}

fun main() {
println(""+ divide(6,2))
try{
println(""+ divide(3,0))
}catch (ae: ArithmeticException){
println("division by 0!")
}
println(""+ divide(3,0))
}

As mentioned in part 1 of this tutorial, the exception type declaration in catch block is a bit diffferent in Kotlin. The results are the similar:

3
division by 0!
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at com.mypackage.MainKt.divide(main.kt:6)
    at com.mypackage.MainKt.main(main.kt:16)
    at com.mypackage.MainKt.main(main.kt)

The only difference is the additional level of stacktrace in the logs... Which I, frankly, don't understand :D May have something to do with my main class configured in the project, being com.mypackage.MainKt?

But what if we want to define out own, custom exception? Let's define a simple one in Java and throw it in our divide method when the divisor is 0 (and then let's catch it instead of the ArithmeticException):

Listing 5 (Java)

import static java.lang.System.out;

class ReallyException extends Exception{
public ReallyException(String errorMessage) {
super(errorMessage);
}
}
public class MainClass {

static int divide(int a, int b) throws ReallyException {
if(b==0)
throw new ReallyException("Really? By 0?");
return a / b;
}

public static void main(String[] args) throws ReallyException {
out.println("" + divide(6, 2));

try{
out.println(""+divide(3,0));
}catch(ReallyException ae){
out.println("Exception message: " + ae.getMessage());
}
out.println("" + divide(3, 0));

}
}

Please not that as the ReallyException is not caught everywhere it could appear, we have to add the throws ReallyException directive to the main() method. The execution result is as follows:

Listing 6 (result)

3
Exception message: Really? By 0?
Exception in thread "main" ReallyException: Really? By 0?
    at MainClass.divide(MainClass.java:12)
    at MainClass.main(MainClass.java:24)

The Kotlin version of the program from Listing 5 would look like this:

Listing 7 (Kotlin)

package com.mypackage

class ReallyException(message:String): Exception(message)

fun divide(a: Int, b: Int): Int{
if(b==0)
throw ReallyException("Really? By 0?")
return a/b
}

fun main() {
println(""+ divide(6,2))
try{
println(""+ divide(3,0))
}catch (ae: ReallyException){
println("Exception message: " + ae.message)
}
println(""+ divide(3,0))
}

Traditional Kotlin brevity shows up: the (trivial) definition of the exception, which in Java took us 5 lines of code, here becomes... just 1 line :) Also, there is not need to declare our main() function throws anything.

One more thing: try in Kotlin, similarly to if and when, is an expression, which means it can return something. To be specific: it returns either the contents of try block in case exception doesn't occur, or catch block content in case of exception. Like this:

Listing 8 (Kotlin)

package com.mypackage

import java.lang.ArithmeticException

fun divide(a: Int, b: Int): Int{
return a/b
}

fun main() {

val result1 =
try { divide(4,2) } catch (e: ArithmeticException) { 9999 }
val result2 =
try { divide(4,0) } catch (e: ArithmeticException) { 9999 }

println(result1)
println(result2)
}

... resulting in:

2
9999

... as the first call simply returns 2, and the second one results in an exception, and therefore returns contents of  catch block, in our case being number 9999.

Saturday, 17 July 2021

Android Java to Kotlin migration by example part 10: higher-order functions

 A higher-order function is a function, which returns another function, or takes another function as parameter.

Today we'll begin with Kotlin code. Kotlin, being much more functional-oriented than Java (although Java is getting more functional since version 8), makes use of higher-order function much more elegant and readable.

Let's consider a mathematical function A, mapping some value to other value, for instance y=x*x (square). We can construct another function B (or functionAMultipliedBy2) which would map any x to functionA(x)*2.

In functional programming we can use a higher-order function in that case: create a function functionB, taking functionA as param. Such function can then be stored like a variable, and called. I guess it's more understandable in the code form. So let us take a look at a program defining our functionMultipliedBy2, getting a Float->Float function (getting float as param and returning a float) as parameter and returning Float->Float function (the function passed as a parameter multiplied by 2). 

Kotlin:

package com.mypackage

fun functionMultipliedBy2(
functionArg: (arg: Float) -> Float): (Float) -> Float
{
val funcToReturn = {a: Float ->functionArg(a)*2}
return funcToReturn
}

fun squareA(arg: Float): Float{
return arg*arg
}

fun main() {
println(squareA(2.0f)) // "4.0"

// we can pass squareA as parameter to functionMultiplied by 2
val squareDoubled = functionMultipliedBy2(::squareA)
// :: because it's class member

// squareDoubled is now a FUNCTION, taking Float
// as param and returning 2* square(param)

// we can simply call it:
println(squareDoubled(2.0f)) // "8.0"
}

The same code in Java would look like this:

import java.util.function.Function;

import static java.lang.System.out;

public class MainClass {

static Function<Float, Float> functionMultipliedBy2(
Function<Float, Float> functionArg)
{
Function<Float, Float> funcToReturn =
input -> functionArg.apply(input) * 2;
return funcToReturn;
}

static float squareA(float arg){
return arg*arg;
}

public static void main(String[] args){
out.println(squareA(2.0f)); // "4.0"

Function<Float, Float> squareDoubled =
functionMultipliedBy2(MainClass::squareA);
// -> ugly

// squareDoubled is an object of type Function
// getting Float as param and returning 2*square (param)

// call looks like this:
out.println(squareDoubled.apply(2.0f)); // "8.0"

}
}

The code execution result is the same in both cases and it's:

4.0
8.0

Please note how the Java code makes use of class Function objects to deal with functions. In Kotlin, we define returned value (or acccepted as argument) as function simply by (Float) -> Float notation.

What's more, in Kotlin we can simply call passed function. A Java Function object has to be used by calling .apply method to it (because it's an object, not a "real" function). I think Kotlin, as more functional-oriented languages, deals with this in much more "natural" way.

The higher-order function can also be used with lambda expressions. In Java:

import java.util.function.Function;

import static java.lang.System.out;

public class MainClass {

static Function<Float, Float> functionMultipliedBy2(
Function<Float, Float> functionArg)
{
Function<Float, Float> funcToReturn =
input -> functionArg.apply(input) * 2;
return funcToReturn;
}

public static void main(String[] args){
Function<Float, Float> squareRoot =
input -> (float)Math.sqrt((double)input);
Function<Float, Float> squareRootDoubled =
functionMultipliedBy2(squareRoot);
out.println(squareRootDoubled.apply(4.0f));
}
}

... as well as in Kotlin:

package com.mypackage

import kotlin.math.sqrt

fun functionMultipliedBy2(
functionArg: (arg: Float) -> Float): (Float) -> Float
{
val funcToReturn = {a: Float ->functionArg(a)*2}
return funcToReturn
}

fun main() {
val squareRoot = {arg:Float -> sqrt(arg.toDouble()).toFloat()}
val squareRootDoubled = functionMultipliedBy2(squareRoot)
println(squareRootDoubled(4.0f))
}

Again, Kotlin is much more concise - and allows us to simply call the function, without using any special .apply() methods.

Friday, 16 July 2021

Android Java to Kotlin migration by example part 9: extension functions

One of Kotlin features which are not available in Java are extension functions. These are the functions which can be used as methods with existing class objects, but are not defined in them. You may already know them if you work with C# - they've been there for some time now.

It's quite useful, when we want to, for instance, define a method we would like to use with String type, but it's not defined by default. Of course, we could inherit from String, but it would mean we have to use the subclass everywhere when we could possibly want to use out new method.

Other solution is to simply create a function, getting our String as param. This is the easiest way this could be done in languages without extension functions (like Java). Let's consider the following function, counting uppercase characters in a string given as its param and returning the result:

Listing 1 (Java)

import static java.lang.System.out;

public class MainClass {

static int howManyUppercase(String string){
int res =0;
for(int i=0;i<string.length();i++)
if(Character.isUpperCase(string.charAt(i)))
res++;
return res;
}

public static void main(String[] args){
String string ="SoMe WoRdS";
out.println(howManyUppercase(string));
}
}

In Kotlin we could write very similar code. But we can also do this:

Listing 2 (Kotlin)

package com.mypackage

fun String.howManyUppercase(): Int{
var res = 0
for(i in 0..this.length-1)
if(this[i].isUpperCase())
res++
return res
}

fun main() {
var string = "SoMe WoRdS"
println(string.howManyUppercase())
}

We define our extension function as we would declare a normal function, but its name is preceded with extended class (in our case that's String ) and a dot.

Our howManyUppercase() becomes basically a String method. It's called like one, and is suggested by the IDE autocompletion.

It's important to remember that extensions are available only in the package they're defined (which makes sense, as it prevents possible conflicts), so it you want to use it outside of that package, the extension (or all the package contents) has to be imported, as shown below (the version with whole package import is commented out):

Listing 3 (Kotlin import)

package com.mypackage2 //!

import com.mypackage.howManyUppercase
// import com.mypackage.* // alternative

class AnotherClass {
fun myStringSomething(): Int{
return "blabla".howManyUppercase()
}
}

The extension functions can "extend" any class - although it seem to make more sense to use them with the standard defined types (as String), which source is not directly available (they're already compiled), you can also extend your own classes.

Please note that as extension function can extend any class, they can also extend Any class :)

In that case, the function can be called for basically every object in the scope of extension function:

package com.mypackage

import java.util.*

fun Any.howManyUppercase(): Int{
if(this is String) {
var res = 0
for(i in 0..this.length-1)
if(this[i].isUpperCase())
res++
return res
}
else
return(-1)
}

fun main() {
var string = "SoMe WoRdS"
println(string.howManyUppercase())
var someDate = Date()
println(someDate.howManyUppercase())
var num: Int = 2
println(num.howManyUppercase())
}

This would return -1 for the objects which are not String. We're using is operator and smart casting, mentioned in the previous post. And although the example above seem to not have much sense (what's the point of extending Any, if de facto only extended type is String?), we can consider the following case:

package com.mypackage

import java.util.*


fun Any.howManyUppercase(): Int{
when (this) {
is String -> {
var res = 0
for(i in 0..this.length-1)
if(this[i].isUpperCase())
res++
return res
}
is CharArray -> {
var res = 0
for(i in 0..this.size-1)
if(this[i].isUpperCase())
res++
return res
}
else -> return(-1)
}
}

fun main() {
var string = "SoMe WoRdS"
println(string.howManyUppercase())
var someDate = Date()
println(someDate.howManyUppercase())
var num: Int = 2
println(num.howManyUppercase())

var arr = string.toCharArray()
println(arr.howManyUppercase())
}

Now if we apply our extension to String or CharArray, it returns what we want. In any other case, it returns -1. If we had some more complex task, it's possible we would like to extend more types this way (using only one method).

Thursday, 15 July 2021

Android Java to Kotlin migration by example part 8: type checks and smart cast

Let's consider the following Java code:

import static java.lang.System.out;

public class MainClass {

static void printPiTimesValue(Object value){
if(value instanceof Float)
out.println(3.14f*(Float)value);
if(value instanceof Double)
out.println(3.14*(Double)value);
if(value instanceof String)
out.println(3.14*Double.parseDouble((String)value));
}

public static void main(String[] args){
printPiTimesValue(2.0);
printPiTimesValue(2.0f);
printPiTimesValue("2.0");
}
}
(I've imported System.out, to write out.println instead of System.out.println every time).

So our printPiTimesValue gets something as param (Object, which in Java can be basically anything), and checks its type with the instanceof operator. If the param is float or double, the method casts it, multiplies by 3.14 and prints value. If it's String, the method casts it to String, then parses Double and prints the multiplied value again.

The program execution results in following output:

6.28
6.28
6.28

Now let's look at the Kotlin couterpart of our code:

package com.mypackage

fun printPiTimesValue(value: Any){
if(value is Float)
println(3.14f*value)
if(value is Double)
println(3.14*value)
if(value is String)
println(3.14*value.toDouble())
}


fun main() {
printPiTimesValue(2.0)
printPiTimesValue(2.0f)
printPiTimesValue("2.0")
}
It works the same way and gives the same results. We use Any in place of Object. Instead of Java instanceof operator, we use Kotlin is, which seems to do the same (return true if the left operand is the type specified by right operand).
Other than that, it looks similar, right?

Well, not exactly.
Where are the casts?
In Java, we had a cast everytime we wanted to use our Object as, for instance, Float, we had to:
1) check its type with instanceof
2) cast it.

In Kotlin - if the type check with  is succeeds, the value is automatically casted using a mechanism called smart cast!
The only case where we actually had change the type is the third if, where the smart cast already casted our value to String, but we still have to parse it as Double (as we had to in Java).


Wednesday, 14 July 2021

Android Java to Kotlin migration by example part 7: companion object problem

 In the previous part we've seen how to use companion objects in Kotlin, giving us something similar to Java/C# static fields and methods.

But there is a problem with it, when using inheritance: companion objects are not accessible from the subclass.

To understand what I mean, look at this Java code:

Listing 1 (Java)

class SuperClass{
static int field = 100;

public static void classMethod(){
System.out.println(
"superclass static method called, field = "
+ field);
}
}
class SubClass extends SuperClass{

public static void subclassMethod(){
field--;
System.out.println("Field value decremented: "
+ field);
}
}

public class MainClass {
public static void main(String[] args){
SuperClass superObject = new SuperClass();
SuperClass.classMethod();

SubClass subObject = new SubClass();
SubClass.subclassMethod();
SubClass.classMethod();
}
}

Code execution result is:

Listing 2 (result)

superclass static method called, field = 100
Field value decremented: 99
superclass static method called, field = 99

It has a superclass, a subclass, both with one static method, the superclass with one static field.

In main method we can instantiate them, and:

- for the superclass instance we can call the superclass static method.

- for the subclass instance we can call both the superclass and the subclass static method.

This makes sense - the subclass instance is the superclass instance. This is how inherintance works, right?

So take a look at this Kotlin code:

Listing 3 (Kotlin)

package com.mypackage


open class SuperClassWithCompanion{
companion object CompanionObj{
var field: Int = 100;
fun classMethod(){
print("superclass companion method called, field = "
+field)
}
}
}
class SubClass: SuperClassWithCompanion(){
companion object CompanionObj {
fun subclassMethod() {
field--;
println("Field value decremented: "
+ field)
}
}
}

fun main() {

val superObject = SuperClassWithCompanion()
SuperClassWithCompanion.classMethod()

val subObject = SubClass()
SubClass.subclassMethod()
//SubClass.classMethod()
}

It's basically the same as the code in Listing 1, we're just using companion objects instead of static fields and methods. So we create a superclass instance, call its static method, the subclass instance, call it's static method (subclassMethod()) and then...

We can't call the classMethod from the subclass. It won't compile, giving the Unresolved reference: classMethod error.

And here is the problem: the companion object is not inheritable. We could say accompanies a particular class, not it's subclass.

The problem, although can be surprising; is - in fact - is not very complicated to solve. As the methods and fields of the companion object are common to all instances, we can just call SuperClassWithCompanion.classMethod() whenever we want to call SubClass.classMethod(). What's more, we can simply add such method (the same name and prototype) in the subclass and call the superclass method there:

Listing 4 (Kotlin)

package com.mypackage


open class SuperClassWithCompanion{
companion object CompanionObj{
var field: Int = 100;
fun classMethod(){
println("superclass companion method called, field = "
+field)
}
}
}
class SubClass: SuperClassWithCompanion(){
companion object CompanionObj {
fun subclassMethod() {
field--;
println("Field value decremented: "
+ field)
}
fun classMethod(){
SuperClassWithCompanion.classMethod()
}
}
}

fun main() {

val superObject = SuperClassWithCompanion()
SuperClassWithCompanion.classMethod()

val subObject = SubClass()
SubClass.subclassMethod()
SubClass.classMethod()
}

Then it works the same as our code from Listing 1:

Listing 5 (result)

superclass static method called, field = 100
Field value decremented: 99
superclass static method called, field = 99

Still, there seems to be some redundancy here, as we have to "manually" call the companion object's methods in the subclass.

The question is - does it make sense? Well, sort of. Tke Kotlin designers purposefully made it impossible to inherit the companion object: because mixing inheritance and static code in Java often led to confusion and errors.

As far as I can see, it doesn't prevent us from doing what we want - maybe just forcing to do it in more explicit way.

 

Monday, 12 July 2021

Android Java to Kotlin migration by example part 6: more OOP (static or not static?)

 Let's consider a following, extremely simple, Java code. We're defining a class with one field, one constructor assiging some value to this field and a method, printing a sentence with this field:

Listing 1 (Java simple class)

class Room{
String name;
public Room(String name){
this.name = name;
}

public void describeStatus(){
System.out.println("There is a room called " + name);
}
}

We can now create two instances of this class (rooms), set them some names in constructors and call the describeStatus() method on each. The complete code:

Listing 2 (Java simple class use)

class Room{
String name;
public Room(String name){
this.name = name;
}

public void describeStatus(){
System.out.println("There is a room called " + name);
}
}

public class MainClass {
public static void main(String[] args){
Room roomOne = new Room("living room");
Room kitchen = new Room("kitchen");

roomOne.describeStatus();
kitchen.describeStatus();

}
}

Giving us result:

Listing 3 (result)

There is a room called living room
There is a room called kitchen

Ok, so how to do the same in Kotlin?

First, the class:

Listing 4 (Kotlin simple class)

class Room{
var name: String = ""

constructor(name: String){
this.name = name
}

fun describeStatus(){
println("There is a room called " + name)
}

}

Which can be also defined as:

Listing 4a (Kotlin shorter one-param constructor)

class Room(var name: String) {

fun describeStatus(){
println("There is a room called " + name)
}
}

The constructor is now just a parameter near the class name, defining a parameter in the same time. The code became much shorter!

We use it this way:

Listing 5 (Kotlin simple class use):

package com.mypackage

class Room(var name: String) {

fun describeStatus(){
println("There is a room called " + name)
}
}

fun main() {
val roomOne = Room("living room")
val kitchen = Room("kitchen")

roomOne.describeStatus()
kitchen.describeStatus()
}

Now let's add a static field and a static method to our Java class. As our class represent a room, such static (which means shared between all the class instance) field can store info about whether alarm is active in a room. The static method setAlarm(Boolean active)  shall therefore (dis-)activate the alarm in every room. We'll also change the describeStatus() method to show the status of alarm. Our class code becomes:

Listing 6 (Java static fields and methods definition):

class Room{
String name;
public Room(String name){
this.name = name;
}
    private static Boolean alarmActive = false;
public static void setAlarm(Boolean active){
alarmActive = active;
}

public void describeStatus(){
System.out.println("There is a room called " + name +
", and the alarm is " +
((alarmActive?"on":"off")+" there"));
}
}

...and we can use it in this way:

Listing 7 (Java static fields and methods use):

public class MainClass {
public static void main(String[] args){
Room roomOne = new Room("living room");
Room kitchen = new Room("kitchen");

System.out.println("Before:");
roomOne.describeStatus();
kitchen.describeStatus();

Room.setAlarm(true);

System.out.println("After:");
roomOne.describeStatus();
kitchen.describeStatus();
}
}

Initially, the alarm is false. We're printing the status for all the rooms. Then we call the  setAlarm() method on the class, setting the static field to true. After that, the status in all the rooms becomes "on":

Listing 8 (result):

Before: There is a room called living room, and the alarm is off there There is a room called kitchen, and the alarm is off there After: There is a room called living room, and the alarm is on there There is a room called kitchen, and the alarm is on there

Now... How to achieve this in Kotlin?

Well, in Kotlin there are no "typical" static fields and methods. Instead, there is a mechanism called a companion object, which serves pretty much the same purpose. The fields "shared" between the instances of the class and the method affecting them, should be defined in such object. The Kotlin counterpart of the code from Listing 5 looks like this:

Listing 9 (Kotlin companion object definition):

class Room(var name: String) {

fun describeStatus(){
println(
"There is a room called " + name +
", and the alarm is " +
(if (alarmActive) "on" else "off") + " there")
}
companion object AlarmStatus{
private var alarmActive: Boolean = false

fun setAlarm(active: Boolean){
alarmActive = active
}
}
}

And the use of it is veery similar to the Java static call:

Listing 10 (Kotlin companion object use):

fun main() {
val roomOne = Room("living room")
val kitchen = Room("kitchen")

println("Before:")
roomOne.describeStatus()
kitchen.describeStatus()

Room.setAlarm(true)

println("After:")
roomOne.describeStatus()
kitchen.describeStatus()
}


Python crash course part 10: inheritance and polymorphism

In the last part we've shown how to create and use a class in Python. Today we're going to talk about inheritance: wchich means cre...