What does a LinkedHashMap create in Kotlin? - kotlin

I am new to Kotlin and came across many instances in documentation where the common, js, native and jvm tags list different return values or class types. Could anyone please explain what exactly does that mean?
Here is an example:
My two question here are:
How are class, typealias and open class different?
Why do they seem to return different values for creating the same thing?

The documentation is telling you what you can expect the declaration of LinkedHashMap to look like, when writing code on different platforms - Kotlin/JS, Kotlin/JVM, Kotlin/Native. The "common" declaration is sort of the "intersection" of the other three - the "common" things among the three, which is useful if you are writing cross-platform code.
To explain each in detail (notice all 3 platforms is a "superset" of common):
Common:
class LinkedHashMap<K, V> : MutableMap<K, V>
LinkedHashMap is a class that has two generic parameters K and V, and it implements MutableMap<K, V>.
JVM:
typealias LinkedHashMap<K, V> = LinkedHashMap<K, V>
LinkedHashMap<K, V> is a typealias (i.e. another name) for Java's java.util.LinkedHashMap<K, V> class. The package name java.util is not shown in the documentation itself, which might be confusing, but you can click on the link to find out :)
Notice that java.util.LinkedHashMap<K, V> implements java.util.Map<K, V>, which when ported to Kotlin, means that it implements MutableMap<K, V>. (I say this because this is one of the things in the common declaration)
JS:
open class LinkedHashMap<K, V> :
HashMap<K, V>,
MutableMap<K, V>
LinkedHashMap is a class that has two generic parameters K and V, and it implements MutableMap<K, V>. It also inherits from HashMap<K, V>, and it is open, which means that you can inherit from it.
Native:
typealias LinkedHashMap<K, V> = HashMap<K, V>
LinkedHashMap<K, V> is just another name for HashMap<K, V> (this time it's Kotlin's kotlin.collections.HashMap, not Java's. Click the link to find out.) Also note that HashMap<K, V> implements MutableMap<K, V> too.
Why do they seem to return different values for creating the same thing?
These are not functions, and they don't return anything. These are declarations for the class LinkedHashMap, and some platforms may declare them differently, because they're different platforms! For example, why would Kotlin/JVM make an entirely new LinkedHashMap, when there is already one in the JDK? So they just say that kotlin.collections.LinkedHashMap is just another name for java.util.HashMap. Another example is Kotlin/Native: it appears that the HashMap that they implemented is already linked, so again, we don't need a totally new class.
As long as what they implement on these different platforms satisfy the requirements of the "common" declaration (namely two generic type parameters K and V, and implements MutableMap<K, V>), they're fine.

First and foremost, most of the information in the docs is not relevant, when on the JVM. If you type LinkedHashMap<String, String>(), you actually (because of the JVM only type alias) create a java.util.LinkedHashMap, thus the way the LinkedHashMap of kotlin is “implemented” on the JVM is using the java built-in. If you call linkedMapOf, however, you get back an instance of the kotlin.collections.LinkedHashMap<K, V> class, but if you look at the reflected type (::class) it is actually still a java.util.LinkedHashMap! So, we can conclude the following out of this:
On the JVM, collection types of the java stdlib are used (because the compiler changes constructor invocations to kotlin collections, to invocations of java ones)
There is a common class or interface that exists so you don’t have to write different code on different platforms, a different type may be used on runtime, however.
When using JS, LinkedHashMap can be overridden (because it is open), and it is the “implementer” of the expected LinkedHashMap type.
When using native targets, because the order is preserved when using a normal HashMap, LinkedHashMap points to there because there is no reason for using a linked hashmap instead of a normal one
Edit: just realized I didn’t really answer your question:
a class is just your regular oop class, but it can’t be overridden because it is open, typealias means that when you reference a certain type it actually “points” to a different type (you can see it as a type rename, or reexport), and an open class is a class that can be extended/overridden
Because of platform-specific implementations. This structure or expect + actual allows you to write common code for all platforms without having to worry about an individual platform.
I hope this answers your questions, let me know if you have any more.

Related

Why do we need an explicit function interface modifier in Kotlin?

consider a SAM defined in Java
public interface Transform {
public String apply(String str);
}
This interface supports lambda to type conversion in Kotlin automatically
fun run(transform: Transform) {
println(transform.apply("world"))
}
run { x -> "Hello $x!!" } // runs fine without any issues
But now consider a Kotlin interface
interface Transform2 {
fun apply(str: String): String
}
Now the only way to invoke the run function would be by creating an anonymous instance of Transform2
run(object : Transform2 {
override fun transform(str: String): String = "hello $str!!"
})
but if we make the Transform2 interface a functional interface then the below is possible
run { str -> "hello $str!!" }
Why the Kotlin compiler cannot automatically type cast lambdas to matching interfaces (just as it does with Java interfaces) without needing to explicitly mark the said interfaces as a functional interface.
I've found some kind of a rationale in a comment in KT-7770:
... treating all the applicable interfaces as SAM might be too
unexpected/implicit: one having a SAM-applicable interface may not
assume that it will be used for SAM-conversions. Thus, adding another
method to the interface becomes more painful since it might require
changing syntax on the call sites (e.g. transforming callable
reference to object literal).
Because of it, current vision is adding some kind of modifier for
interfaces that when being applied:
Adds a check that the interface is a valid SAM
Allows SAM-conversions on call sites for it
Something like this:
fun interface MyRunnable {
fun run()
}
Basically, he is saying that if the SAM conversion were done implicitly by default, and I add some new methods to the interface, the SAM conversions would no longer be performed, and every place that used the conversion needs to be changed. The word "fun" is there to tell the compiler to check that the interface indeed has only one abstract method, and also to tell the call site that this is indeed a SAM interface, and they can expect the author to not suddenly add new abstract methods to the interface, suddenly breaking their code.
The thread goes on to discuss why can't the same argument can't be applied to Java, and the reason essentially boils down to "Java is not Kotlin".
This is speculation, but I strongly suspect one reason is to avoid encouraging the use of functional interfaces over Kotlin's more natural approach.
Functional interfaces are Java's solution to the problem of adding lambdas to the Java language in a way that involved the least change and risk, and the greatest compatibility with what had been best practice in the nearly 20 years that Java had existed without them: the use of anonymous classes implementing named interfaces. It needs umpteen different named interfaces such as Supplier, BiFunction, DoublePredicate… each with their own method and parameter names, each incompatible with all the others — and with all the other interfaces people have developed over the years. (For example, Java has a whole host of interfaces that are effectively one-parameter functions — Function, UnaryOperator, Consumer, Predicate, ActionListener, AWTEventListener… — but are all unrelated and incompatible.) And all this is to make up for the fact that Java doesn't have first-class functions.
Kotlin has first-class functions, which are a much more general, more elegant, and more powerful approach. (For example, you can write a lambda (or function, or function literal) taking a single parameter, and use it anywhere that you need a function taking a single parameter, without worrying about its exact interface. You don't have to choose between similar-looking interfaces, or write your own if there isn't one. And there are none of the hidden gotchas that occur when Java can't infer the correct interface type.) All the standard library uses function types, as does most other Kotlin code people write. And because they're so widely-used, they're widely supported: as part of the Kotlin ecosystem, everyone benefits.
So Kotlin supports functional interfaces mainly for compatibility with Java. Compared to first-class functions, they're basically a hack. A very ingenious and elegant hack, and arguably a necessary one given how important backward compatibility is to the Java platform — but a hack nonetheless. And so I suspect that JetBrains want to encourage people to use function types in preference to them where possible.
In Kotlin, you have to explicitly request features which improve Java compatibility but can lead to worse Kotlin code (such as #JvmStatic for static methods, or casting to java.lang.Object in order to call wait()/notify()). So it fits into the same pattern that you also have to explicitly request a functional interface (by using fun interface).
(See also my previous answer on the subject.)

Why is Kotlin `Any` a Class not an Interface?

Kotlin any is a class, with the methods from Java Object
open class Any() {
open operator fun equals(other: kotlin.Any?): kotlin.Boolean { /* compiled code */ }
open fun hashCode(): kotlin.Int { /* compiled code */ }
open fun toString(): kotlin.String { /* compiled code */ }
}
Why is this?
I would have predicted that, as primitives are considered Any, but aren't actually Object, it would have better to have Any an interface that they pretended to implement rather than an class they pretended to inherit.
If Any were an interface, but every single class and interface implicitly inherits from it, then it would have to have default implementations of equals and hashcode, which wouldn't make conceptual sense for an interface.
Also, since every interface would inherit from Any, there would be a conflict when a class inherits from multiple interfaces. Which super-type implementation of equals and hashcode would be used? Multiple inheritance of interfaces is a very common situation, so you would be dealing with the complexity of conflicting interface function signatures very frequently rather than once in a blue moon.
Object does not exist in Kotlin. That is a Java concept. The fact that after compilation, the byte code is compatible with Java types such as Object, is irrelevant from a Kotlin language perspective.
Nat Pryce wrote a really short, very readable article explaining the Kotlin type system.
http://www.natpryce.com/articles/000818.html
In it you'll notice he says:
Any is the equivalent of Java’s Object class.
But they are not the same thing. The Java and Kotlin type systems are entirely separate things.
Any is not an interface because it serves nearly the same purpose as Java's Object. In Kotlin, Any? is the type that includes all types which can be represented in the type system. And Any is the type that includes all types except the null value. So really, Any? is Kotlin's Object. It is a type for the same reason that Object is a type.
As others have mentioned, Kotlin doesn't have primitives in its type system, so there is no need for them to inherit or pretend to inherit any interface. They don't exist.

Is it possible to write default implementation of equals method in a Kotlin interface?

Is it possible to write default implementation of equals method in a Kotlin interface?
I have this code:
interface User {
val id: String
}
And I want all the classes implementing User to being compared using id property. Something like this:
interface User {
val id: String
fun equals(other: Any?) : Boolean {
//check type and stuff
return id == other.id
}
}
I know I can (and maybe should) use an abstract class, but I have to deal with this scenario now.
Thank you
No, I'm afraid that's not possible.
If you try your code, the compiler complains that:
        'equals' hides member of supertype 'Any' and needs 'override' modifier
And if you add the override modifier:
        An interface may not implement a method of 'Any'
The reasons are a bit obscure, and are inherited (!) from Java.
Originally, interfaces could only contain abstract methods (and constant fields).  When the ability to specify method implementations in interfaces was added, it was done in a way so as not to break existing code, so they only apply where classes don't already have an implementation.  (In Java they're called ‘default’ methods to reinforce that.)  If a class has an implementation, either defined within the class or in a superclass, that gets used, and the default is ignored.
There are a few corner cases, though: the methods defined in Object (Java's equivalent of Kotlin's Any).  Those are clone(), equals(), finalize(), getClass(), hashCode(), notify(), notifyAll(), toString(), and wait().  (Most of those are rarely used directly these days, but of course equals(), hashCode(), and toString() are very important.)
Because those methods are defined in Object, every class has a direct implementation of them (either from Object or some subclass).  And so the interface's default implementation can never be used.
Exactly the same applies to Kotlin/JVM and the corresponding methods defined in Any — in fact, the compiler makes it explicit by giving an error if you try to provide a default implementation of any of those methods, as shown above.
This is a shame, because there are cases where a default implementation of equals(), hashCode(), and/or toString() would be extremely useful!  But it would introduce complexity, fragility, and some surprising corner cases; see this answer for an authoritative explanation.

what is the benefit of extension fun in kotlin?Is it good to leak a fun to other classes?

Is it a good idea to cut my code anywhere around the project in other classes using extension functions?
I mean what is the point?For what exactly a class fun can leak to other classes?
Friends, I'm new to Kotlin and I appreciate if anyone can provide a real example of using extension fun in kotlin.
class Car{
//any code you imagine
}
class Garage{
//any code
fun Car.boost(){
//boost implementation
}
}
As stated in Kotlin Coding Conventions, extension functions are a good practice:
Use extension functions liberally. Every time you have a function that
works primarily on an object, consider making it an extension function
accepting that object as a receiver.
There are a few reasons for that:
Extension functions keep your class small and easy to reason about
Extension functions force you to have good API, since they cannot access any private members of your class
Extension functions have zero cost on performance, since they're simply rewritten by Kotlin compiler into static methods, with method receiver (the class you're extending) as its first argument

Using default function implementation of interface in Kotlin

I have a Kotlin interface with a default implementation, for instance:
interface Foo {
fun bar(): String {
return "baz"
}
}
This would be okay until I try to implement this interface from Java. When I do, it says the class need to be marked as abstract or implement the method bar(). Also when I try to implement the method, I am unable to call super.bar().
Generating true default methods callable from Java is an experimental feature of Kotlin 1.2.40.
You need to annotate the methods with the #JvmDefault annotation:
interface Foo {
#JvmDefault
fun bar(): String {
return "baz"
}
}
This feature is still disabled by default, you need to pass the -Xjvm-default=enable flag to the compiler for it to work. (If you need to do this in Gradle, see here).
It really is experimental, however. The blog post warns that both design and implementation may change in the future, and at least in my IDE, Java classes are still marked with errors for not implementing these methods, despite compiling and working fine.
Please see the related issue.
There is a recommendation in the comments:
Write your interface in Java (with default methods) and both the Java and Kotlin classes correctly use those defaults
If you know you won't be overriding the function in any implementations of your interface, you can use extension functions as a nice workaround for this issue. Just put an extension function in the same file as the interface (and at the top level so other files can use it).
For example, what you're doing could be done this way:
interface Foo {
// presumably other stuff
}
fun Foo.bar(): String {
return "baz"
}
See the docs on extension functions for more information about them.
One "gotcha" worth noting:
We would like to emphasize that extension functions are dispatched statically, i.e. they are not virtual by receiver type. This means that the extension function being called is determined by the type of the expression on which the function is invoked, not by the type of the result of evaluating that expression at runtime.
Put simply, extension functions don't do what you might expect from regular polymorphism. What this means for this workaround is that the default function cannot be overridden like a regular function. If you try to override it, you'll get some weird behavior, because the "overridden" version will be called whenever you're dealing explicitly with the subclass, but the extension version will be called when you're dealing with the interface generically. For example:
interface MyInterface {
fun a()
}
fun MyInterface.b() {
println("MyInterface.b() default implementation")
}
class MyInterfaceImpl : MyInterface {
override fun a() {
println("MyInterfaceImpl.a()")
}
fun b() {
println("MyInterfaceImpl.b() \"overridden\" implementation")
}
}
fun main(args: Array<String>) {
val inst1: MyInterface = MyInterfaceImpl()
inst1.a()
inst1.b() // calls the "default" implementation
val inst2: MyInterfaceImpl = MyInterfaceImpl() // could also just do "val inst2 = MyInterfaceImpl()" (the type is inferred)
inst2.a()
inst2.b() // calls the "overridden" implementation
}
Since Kotlin 1.4.0, you can use one of the following compiler flags:
-Xjvm-default=all
-Xjvm-default=all-compatibility (for binary compatibility with old Kotlin code)
This will enable JVM default method compilation for all interfaces.
If you want to read up on how to set these flags in your IDE or Maven/Gradle project, check out the documentation on compiler options.
Progress on this is being tracked in issue KT-4779, which also includes a helpful summary of the current state. The #JvmDefault annotation and the older -Xjvm-default=enable and -Xjvm-default=compatibility compiler flags should no longer be used.
Unlike earlier version of Java8, Kotlin can have default implementation in interface.
When you implement Foo interface into a Java class. Kotlin hides those implementation of interface method. As stated here.
Arrays are used with primitive datatypes on the Java platform to avoid the cost of boxing/unboxing operations. As Kotlin hides those implementation details, a workaround is required to interface with Java code
This is specific for Arrays in above link but it also applies to all the classes (May be to give support for earlier version of Java8).
EDIT
Above explanation is opinion based.
One thing i came across and that is the main reason.
Kotlin binaries were compiled with java bytecode version 1.8 without default methods in interfaces. And they are facing critical issue solving it.