Why do we use only [List, Map, Set] collections in Kotlin? - kotlin

I've been learning Kotlin and I've faced with Collections API. Before Kotlin I'd been learning Java and I know that in Java there's a lot of different types of Collections API. For example, instead of general List, Map, Queue, Set we use ArrayList, HashMap, LinkedList, LinkedMap and etc. Though in Kotlin we only use general types like Map, List, Set but also we can use HashMap and etc. So, what's going on there? Can you help me to figure out?

While Kotlin's original and primary target is the JVM, there is a huge push by JetBrains to make it multiplatform, and support JS and Native as well.
If you're using Kotlin on the JVM, the implementations of any collections you're using will still be the original JDK classes, e.g. java.util.ArrayList or java.util.HashSet. These are not reimplemented by the Kotlin standard library, which has some great benefits:
These are well-tested implementations, which are maintained anyway.
Using the exact same classes makes interop with Java a breeze, as you can pass them back and forth without having to perform conversions or mapping of any kind.
What Kotlin does do is introduce its own collection semantics over these existing implementations, in the form of the standard library interfaces such as List, Map, MutableList, MutableMap and so on. A small bit of compiler magic makes it so that these interfaces are implemented by the existing JDK classes as well.
If you don't need a specific implementation of a certain type of collection, you can use your collections via these interfaces plus the respective factory methods of the standard library (listOf, mapOf, mutableListOf, mutableMapOf, etc.). This keeps your code more generic, and independent of the concrete underlying implementations. You don't know what specific class the standard library mutableListOf function will create for you, only that it will be an object that satisfies the contract of the MutableList interface.
You should basically use these interfaces by default in your code, especially in public API:
In the case of function parameters, this lets clients provide the function with whatever implementation of the collection they wish to give you. If your function can operate on anything that's a List, you should ask for just that interface - no reason to require an ArrayList or LinkedList specifically.
If this is a return type, using these interfaces lets you change the specific implementation that you create internally in the future, without breaking client code. You can promise to just return a MutableList of things, and what implementation backs that list is not exposed to your clients.
If you look at all the collection handling functions of the Kotlin standard library, you'll see that on the surface, they almost exclusively operate on these interfaces. If you dig down deep enough, you'll find ArrayList instances being created, but this is not exposed to the client code, as it doesn't have to care about the concrete implementation most of the time.
Going back to the multiplatform point once more, if you write your code in a way such that it only relies on Kotlin standard library defined types, that code will be easily usable for non-JVM targets. If you reference kotlin.MutableList in your imports, that can immediately compile to JS code, because there's a Kotlin standard library implementation of that interface on each platform. Whether that maps to an existing class directly, wraps an existing class somehow, or is implemented for Kotlin from scratch, again, doesn't have to concern you. But if you refer to java.util.TreeSet in your code, that won't fly for the JS target, as the Java platform classes are not available there.
Can you still use classes such as java.util.ArrayList directly? Of course.
If you don't see your code going multiplatform at some point, using Java collections directly is perfectly okay.
If you need a specific implementation for a List or a Set for performance reasons, sometimes you'll have to use the Java classes directly.
Interestingly, in recent releases of Kotlin, these specific types of implementations (such as an array based list) are wrapped under standard library typealiases too, so that they're platform independent by default: see kotlin.collections.ArrayList or kotlin.collections.HashSet for examples of this. These Kotlin-defined types will usually show up first in IntelliJ completion, so you'll find yourself being pushed towards using them wherever possible. Same thing goes for most exceptions, e.g. IllegalArgumentException.
TL;DR: You can use either Kotlin collection types of Java types in Kotlin, but you should probably do the former whenever you can.

Related

Why is Kotlin’s ArrayDeque a concrete class without an interface?

Of course, I can use the whole Java standard library as long as I stay on the JVM, but quite often Kotlin offers equivalent classes, sometimes shadowing Java’s classes (and using them behind my back). As such, Kotlin offers an ArrayDeque to replace Java’s ArrayDeque.
Now, the good old java.util.ArrayDeque, being in line with the other collection classes, implements the interface java.util.Deque (it’s actually one of four such implementations in java.util. That is usually considered good practice, if you just care for a Deque you should not need to know whether it is implemented using an array or a list.
However, the new-fangled kotlin.collections.ArrayDeque (where actually the package name is redundant, since it is accessible without) has no interface it implements, apart from MutableList, which is too generic.
I don’t want to trigger opinion-based answers here, even if I can already imagine a few of them. Rather, I wonder if there may exist a hard technical reason to decide against using a strategy used in other places of the Kotlin standard library itself.

Why they integrate stream API to collection framework in java 8

When learning about design patterns I heard that delegation is better than inheritance in most cases.
Thus I wonder why the java8 team made the decision to integrate Stream API into the existing Collections framework instead of using delegation (construct a Stream based on the given Collection)?
Especially by doing so, they have to introduce the new concept of Interface's default method implementation that in turn, blur out the semantic of Interfaces vs. Abstract classes?
delegation is better than inheritance
I think you have wrote some wrong in your question. Actually, the correct form is Composition over Inheritance.
Indeed, Collection#stream & Collection#spliterator is designed for applying Factory Method pattern. which means subclasses can provided it own Stream/Spliteartor instance to enable features & promote the performance purpose in java.
IF there is no such factory methods in Collection, you must back to procedure code and check the actually type to create appropriate Streams in runtime.
You only see the default methods declared on Collection, have you saw the override methods on sub-classes, for example:
Collections#nCopies uses a CopiesList as below to create a Stream<E> by IntStream to promote the performance.
public Stream<E> stream() {
return IntStream.range(0, n).mapToObj(i -> element);
}
ArrayList#spliterator uses a ArrayListSpliterator as below to create a fail-fast spliterator:
public Spliterator<E> spliterator() {
return new ArrayListSpliterator<>(this, 0, -1, 0);
}
First of all, the support for default and static methods in interfaces was not added only to support the stream() method in the Collection interface.
It is a natural desire to provide utility methods and useful defaults when defining interface, leading to the pattern of having two different classes to host them, the interface and an associated utility class. In the case of useful defaults, implementors were still required to write delegation method to use them. Of course, this would even become worse with functional interfaces restricted to a single method. See also this answer.
So when you consider the language feature of default methods as already existing, the choice of using it in the Collection API for convenience is not so big. It still is delegation, just with a convenient entry point. It’s not different to, e.g. String.format(…) delegating to the java.util.Formatter facility or String.replaceAll delegating to java.util.regex.
But the Stream API can’t run on its own without any active support from the Collection API side. The minimum it would require, is an Iterator from the Collection. The Iterator has been superseded by Spliterator for the Stream API, but whether a Collection provides an Iterator or a Spliterator is not a fundamental design change. It’s something that lies in the collection’s responsibility. There is a default method creating a Spliterator from an Iterator to allow every existing collection to work with the new framework out-of-the-box, but each Collection implementation has the opportunity to override that method, providing a better suited, potentially more efficient Spliterator implementation. Most of the JRE’s standard collection implementations and nowadays a lot the 3rd party collections use that opportunity.
Being overridable is a property of the default methods that you can’t emulate with static methods in another class or package. So it actually works the other way round. E.g. you can still invoke the old Collections.sort methods, but they will delegate to the new List.sort default method, which can be overridden with a more efficient implementation.
Like you normally don’t deal with an Iterator manually when using for(Variable v: collection) …, you don’t deal with a Spliterator manually, when using collection.stream(). … .
Providing a framework that is intended to be used by millions of users is always about balancing ease of use and following strict guidelines.
And the very first point to understand: favor composition over inheritance is a good practice. But that doesn't mean that always prefer composition.
The new streams architecture is intended as a new core building block of the Java APIs. In that sense: it is a natural choice to allow turning collections into streams via a member function.
Beyond that, it seems that the people behind the java language favor fluent interfaces. In that sense they probably prefer
list.stream(). stream operations
over
Streams.stream(list). stream operations
And of course: when you think about the one suggestion I put up here how to alternatively implement a conversion from list to stream - that would only work for the known collections classes. So another concept would be required, like
YourSpecialStreamCreator.(yourSpecialCollection).stream()
whereas the fact that the interface based stream()method allows you to simply #Override the default implementation when your special collection implementation has a need to do so. But you can still use all the other things around streams in that interface!
Beyond that: the idea of default methods in interfaces actually helps with many problems. Yes, they were needed to add those new functionality to interface - but heck: adding new methods to interfaces is something that most people would like to do at some point. So having a clear, defined way backed into the core language is just extremely helpful.
My personal two cent here: adding V2, V3, ... interfaces like:
interface MyFunctionality { ...
interface MyFunctionalityV2 extends MyFunctionality {
void someNewThing();
is just ugly and painful.
Why they integrate stream API to collection framework in java 8
Because before Java 8, Java collections features had a strong delay on concurrent languages such as C#, Scala, Ruby, etc... that provides out of the box and most of time in a conciser way a rich set of functional methods for collections but also pipeline processing for collections.
Thus I wonder why the java8 team made the decision to integrate Stream
API into the existing Collections framework instead of using
delegation (construct a Stream based on the given Collection)?
It would make the API of Stream less fluent, with more boiler plate code and as a consequence, it would not make intrinsically evolve the Java Collections features.
Imagine writing this code with a wrapper at each time :
List<String> strings = new ArrayList<>();
...
Streams.stream(strings).filter(....);
instead of :
List<String> strings = new ArrayList<>();
...
strings.stream().filter(....);
Imagine with a chained stream :
List<Integer> listOne = new ArrayList<>();
List<Integer> listTwo = new ArrayList<>();
...
List<int[]> values = Streams.stream(listOne)
.flatMap(i -> Streams.stream(listTwo)
.map(j -> new int[] { i, j }))
.collect(Collectors.toList());
instead of
List<Integer> listOne = new ArrayList<>();
List<Integer> listTwo = new ArrayList<>();
...
List<int[]> values = listOne.stream()
.flatMap(i -> listTwo.stream()
.map(j -> new int[] { i, j }))
.collect(Collectors.toList());
Especially by doing so, they have to introduce the new concept of
Interface's default method implementation that in turn, blur out the
semantic of Interfaces vs. Abstract classes?
It may be disconcerting at the beginning but finally it gives a powerful way to make evolve an API without breaking the client code using the old API.
Default methods should not be considered as a way to create abstract classes with common processings for all subclasses but a way to make evolve an API without breaking the compatibility with clients of older versions of the API.
Extract of the documentation on default methods :
Default methods enable you to add new functionality to the interfaces
of your libraries and ensure binary compatibility with code written
for older versions of those interfaces.
You could view in this way- If lambda expressions were introduced in back jdk1.2 then the way Collection api must have designed/implemented will be like the 'stream library' or in another words stream is enhanced collection.
Most of the existing codes are using Collection APIs as the data source. Therefore no one is going to use stream if stream is not able to create from a Collection APIs. For that reason they have to modify the existing interface. 'default' methods avoided the breaking of all existing interface and allowed to enhance your code without any issues.
More over 'default methods' provided a way to enhance your interface in future also. Still there are huge differences between default methods in interface and abstract classes.
There are some methods in some interface's where implementation will be same in most of the inherited classes. In that case you can implement it as default method if possible. Once you start using default method you will love it :)
Last but not least "Language should always evolve; it should not stuck up on what you designed 20 years ago" :)

Is creating a module with interfaces only a good idea?

Creating a module (bundle, package, whatever) with only interfaces seems to me a strange idea. Yet, I don't know the other best solution to solve the following architectural requirement.
There often appears a need for a set of utilities. In many projects I can see the creation of "utils" folder, or even a seperate package (module) with frequently used ones.
Now consider the idea that you don't want to depend upon a concrete utils set. Instead you, therefore, use interfaces.
So you may create the whole project, with multiple modules, dependent only on the "Utils-Interfaces" set, which could be a separate module. Then you think you can re-use it in other projects, as these utils are frequently used.
So what do you do? Create a seperate module (package, bundle...) with interfaces with definitions of the methods to be implemented by concrete utility-classes? And re-use this "glue-interfaces-packages" (possibly with other "glues", such as bridges, providers etc.) in your various other projects? Or is there a better way to design the archictecture regarding the utilities that could be easily switched from one to another?
It seems a bit odd to have an interface for utility methods as it should be clear what they do. Also in most language you won't have static dispatch anymore. And you wouldn't solve a problem by having interfaces for utility methods. I think it would make more sense to look for a library doing the same thing or writing your own if such functionality isn't already implemented. Very specific things should be tied to the project, though.
Let's look at an example in Java:
public static boolean isDigitOnly(String text) {
return "\\d+".matches(text);
}
Let's assume one would use an interface. That would mean that you have to have an instance of such an implementation, most likely a singleton. So what's the point of that? You would write the method head twice and you don't have any advantage; interfaces are used for loose coupling, however such generic utility methods aren't bound to your application.
So maybe you just want to use a library. And actually there is one for exactly this use case: Apache Commons. Of course you may not want to include such a big library for a single method. However, if you need this many utility methods you may want to use it.
Now I've explained how to use and reuse utility methods; however, a part of your question was about using different implementations.
I can't see many cases you wanted this. If, for example, you have a method specific to a certain implementation of sockets, you may instead want
A) the utility method as a part of the API
B) an interface for different socket implementations on which you have one common utility method
If you cannot apply this to your problem, it's probably not a utility method or I didn't consider it. If you could provide me with a more specific problem I'd be happy to give you a more concrete answer.

extending objects at run-time via categories?

Objective-C’s objects are pretty flexible when compared to similar languages like C++ and can be extended at runtime via Categories or through runtime functions.
Any idea what this sentence means? I am relatively new to Objective-C
While technically true, it may be confusing to the reader to call category extension "at runtime." As Justin Meiners explains, categories allow you to add additional methods to an existing class without requiring access to the existing class's source code. The use of categories is fairly common in Objective-C, though there are some dangers. If two different categories add the same method to the same class, then the behavior is undefined. Since you cannot know whether some other part of the system (perhaps even a system library) adds a category method, you typically must add a prefix to prevent collisions (for example rather than swappedString, a better name would likely be something like rnc_swappedString if this were part of RNCryptor for instance.)
As I said, it is technically true that categories are added at runtime, but from the programmer's point of view, categories are written as though just part of the class, so most people think of them as being a compile-time choice. It is very rare to decide at runtime whether to add a category method or not.
As a beginner, you should be aware of categories, but slow to create new ones. Creating categories is a somewhat intermediate-level skill. It's not something to avoid, but not something you'll use every day. It's very easy to overuse them. See Justin's link for more information.
On the other hand, "runtime functions" really do add new functionality to existing classes or even specific objects at runtime, and are completely under the control of code. You can, at runtime, modify a class such that it responds to a method it didn't previously respond to. You can even generate entirely new classes at runtime that did not exist when the program was compiled, and you can change the class of existing objects. (This is exactly how Key-Value Observation is implemented.)
Modifying classes and objects using the runtime is an advanced skill. You should not even consider using these techniques in production code until you have significant experience. And when you have that experience, it will tell you that you very seldom what to do this anyway. You will know the runtime functions because they are C-based, with names like method_exchangeImplmentations. You won't mistake them for normal ObjC (and you generally have to import objc/runtime.h to get to them.)
There is a middle-ground that bleeds into runtime manipulation called message forwarding and dynamic message resolution. This is often used for proxy objects, and is implemented with -forwardingTargetForSelector, +resolveInstanceMethod, and some similar methods. These are tools that allow classes to modify themselves at runtime, and is much less dangerous than modifying other classes (i.e. "swizzling").
It's also important to consider how all of this translates to Swift. In general, Swift has discouraged and restricted the use of runtime class manipulation, but it embraces (and improves) category-like extensions. By the time you're experienced enough to dig into the runtime, you will likely find it an even more obscure skill than it is today. But you will use extensions (Swift's version of categories) in every program.
A category allows you to add functionality to an existing class that you do not have access to source code for (System frameworks, 3rd party APIs etc). This functionality is possible by adding methods to a class at runtime.
For example lets say I wanted to add a method to NSString that swapped uppercase and lowercase letters called -swappedString. In static languages (such as C++), extending classes like this is more difficult. I would have to create a subclass of NSString (or a helper function). While my own code could take advantage of my subclass, any instance created in a library would not use my subclass and would not have my method.
Using categories I can extend any class, such as adding a -swappedString method and use it on any instance of the class, such asNSString transparently [anyString swappedString];.
You can learn more details from Apple's Docs

Compile function with curry in groovy

I want to provide some functionality for compiling sources of a specific kind (e.g. java).
As the process of compilation needs additional information i need to give in some more arguments and not only the sourcefile. E.g. working directory, compiler parameters and so on.
There are two ways in my mind how to design it:
Using OOP, that means creating a compiler class, saving the
additional arguments when constructing a specific compiler object
that can then be used for compiling by just providing the sourcefile
Not creating a class for creating objects but just a (static final?)
closure in a class and then using curry to pass in the needed
arguments and returning another compile function which can then be
provided by for example just the sourcefile to compile it
What are the pros and cons? Is there maybe an even better way to get things done?
According to me it only depends on if this should be done well or it's just a kind of a proof of concept. If there will be multiple source files with different types, then it's better to create well-designed, robust class hierarchy. Otherwise You can use a bunch a predefined closures if suites your needs.
Mind the fact that these two solutions are not mutually exclusive. You can still create a robust class hierarchy that will be using predefined closures internally.