“We don’t even try to run the old code, we don’t have such a task in principle” - Roman Elizarov about the development of Kotlin

    If you want to figure out something, learn right away from the best. Today, my questions are answered by the god Korutin and concurrency, Roma elizarov Elizarov. We talked not only about Kotlin, as you might think, but also about a bunch of related topics:

    • Golang and gorutiny;
    • JavaScript and its applicability for serious projects;
    • Java and Project Loom;
    • Olympiad programming on Kotlin;
    • how to learn programming;
    • and other exciting things.



    Kotlin - well done!


    Hey. First give a few words about yourself. Have you been doing Kotlin for a long time?


    I have a long history with Kotlin. In 2010, Kotlin began as a project in JetBrains, where I was not working at the time. But Max Shafirov (he was engaged in Kotlin then and was one of the initiators of this movement inside JetBrains) invited me to become an external expert and look at the design, comment. Initially, the language was designed to solve its problems, because JetBrains has its own large base of Java code, with understandable problems that the code always has, and I wanted to make a language for myself to write my code more pleasantly, more efficiently, with fewer errors. Just spend at upgrading. Naturally, this quickly developed into the idea that once we have such problems, it means that others also have such problems, and they needed confirmation from other people that they were on the right path.

    I was invited as an expert, so that I looked and checked what was happening with what was needed. About nullability - I insisted on doing this, because at that moment it was obvious to me that if you write Java, there are a lot of problems, but nullability is the main problem that you constantly encounter.

    I did not participate in the work of the team, I just occasionally glanced, participated in competitions at the Kotlin (Kotlin Cup). I have been doing competitions all my life, but I myself did not actively participate even then. For example, I would not reach the final of competitions like the Facebook Hacker Cup, the form is not due to the fact that I no longer participate in competitions on a permanent basis. And I took part in the Kotlin Cup, and since it did not gather a wide audience, I easily reached the final.

    At that time (2012-2013), Kotlin was a sad sight from the point of view of tuling, because everything was slowing down there. Since then, the team has done a great job. I joined the team two years ago, right after the release of 1.0 and before Google officially recognized the language. In the team, I took up all kinds of asynchrony and corutines, just because it turned out that I had the right experience, I worked a lot in DevExperts with all sorts of large enterprise systems, and there was a lot of asynchrony and communication. Therefore, I was well aware of the problem areas - what needs to be repaired and what hurts people. It is very well laid down for the needs of Kotlin, because it hurts not only for us. It hurts everyone. Even in the JVM, Project Loom took over, which seemed to hint that it hurts everyone. I still do the Kotlin libraries,


    That is, you are mainly engaged in libraries, not a compiler, and that’s all?


    No, I am engaged in the compiler so far as. I communicate with the guys, and our library team dogfudit everything that they do in the compiler. We are also customers, we create a lot of features, when we come across some flaws, and we are testers of the first line of everything new that rolls out.


    So, if you go to YouTrack, filter on you, you can find a lot of interesting things.


    Yes, you can find a bunch of all sorts of tasks, because I constantly bump into something.


    You mentioned Project Loom. He was made by the guy who made Quasar. From the side it looks very funny, I just wanted to write an article about Loom on Habra. Can you tell me something about him?


    I saw the presentation, the idea is clear. Korutiny and asynchronous programming is needed by all. For example, in the past, the JPoint guys from Alibaba told how they hacked the JVM and screwed the hotspot fayber themselves, just rolling a patch there, which even they didn't write, but some guys before them. They already then filed for themselves. Wonderful report. Highly recommend.


    Do you recommend doing this?


    So to do in enterprise accounts. Each large enterprise, above a certain size, when several thousand people start working for you (and for some less), keep your OpenJDK hack. And of course, if you have business-critical yuzkeys, then why not hack something for yourself, I do not see any big problem in this. Not that I recommend it, but I have to. If there are no lightweight streams in HotSpot, what to do? This, in fact, suggests that people need what is overdue. And the feedback that we receive on Korutin also suggests that yes, it is overdue, people need lightweight flows, people have a wagons for lightweight flows. The fact that they should somehow be supported in the JDK is long overdue, and in this sense I have no doubt that when Loom comes to production sooner or later, this will be in demand. There are people who need it. There are people,


    I saw a frequent problem - you have some kind of web server, a lot of people are knocking at it, and it starts blocking on threads.


    This is a fairly typical problem. And the web server, and application-server, and backend. If you look at the same Alibaba presentation, why this business was needed, then they don’t have a web server, they have a classic enterprise architecture, they have all sorts of services written on the backend for Java, these services are under load. I worked with the same in DevExperts: services under load, you receive requests that you do not handle, because in the modern world you have everything connected. And you don’t process this request yourself, and you also call and wait for 100,500 other services until they respond. And if these services slow down, then you have a lot of threads waiting. You cannot afford to have tens of thousands of these waiting streams. And you get it just because of some nonsense the following: one service that you use slows down, and a lot of threads are waiting for you.

    One of the reasons why people migrate en masse to Go is not because the language is good, but because there are lightweight flows out of the box, and there is no such problem anymore: the gorutines can wait, and they are worthless. In the same Alibaba, the solution they implemented is generally stupid of all the stupid ones. They are not very lightweight in the sense that they allocate one large stack of 2 megabytes each, hacking HotSpot, so that these stacks can be switched. They save physical flow, but do not save stacks. And for them the solution works - by the way, it is very simple, their HotSpot patch, as far as I understand, is not very big. The guys from Loom started something more global. They decided to save not only on physical flows, but also on the stack, so as not to spend 2 megabytes per stream. In the prototype, the current stack passes through HotSpot, it is copied into a small hippie structure. And they can further reuse this physical stack for other purposes.


    But there is such a cunning hack: when you come back to the performance, they copy it not all, but only the very top.


    Yes, there are hack cars and optimizations. What is the result of this is very difficult to say. Because using the example of the copying approach, the following problem immediately arises: what to do with native calls? From inside a native call, you can no longer copy a stack of a native call. There is no such problem in the Alibaba approach. Native, not native - what's the difference, you just uncoupled that stack completely and left it alone, picked up another stack, everything works. And here it’s too early to say what happens or fails, sometimes you can live with this native stack, sometimes it is impossible - it’s too early to say at this stage. For example, how it is implemented in Go - there is a completely different mechanism. As long as you execute the gosh code, small gosh stacks are used. Accordingly, when the ghost runtime calls a function, it looks at how much the stack needs. If the current stack is missing, he perevydelyaet - increases the size of the selected stack. If, accordingly, you make a native call, then they already take some large native stack from a certain pool and use it.


    And for the code too?


    Never mind. They can simply switch to a large native stack, if you need to call some external function, for which it is unclear how much stack is needed. And when you execute a gosh code, you know how much stack you need, so we can run it on a small stack. There is a completely different approach. We do not copy, but immediately execute on a small stack. In fact, there is not much difference between these approaches as long as you occasionally fall asleep.

    We are constantly asked the question: “What is faster? What fits? How do you do this in Korutin? ”We in Korutin do not hack JVM. Our goal is to make it work under a regular JVM. And to work on Android too. There is an ART, which also knows nothing about korutinakh. And so, naturally, we have to use handles to generate bytecode, which does something very similar to copying the stack, which Loom does, only we do it in bytecode. We take it when he already zassenditsya. We take the stack, unwind and copy to hip. We are not on the runtime that would do this for us, we have generated bytecode that does it. It saves and restores the condition of cortina. Due to the fact that we are not doing runtime, naturally, we have more of an overhead projector. In runtime you can do everything faster. On the other hand, if you use Korutin for asynchronous programming, then you need to fall asleep, if you left to wait for a response from some service, and send a request to some service is so expensive that the entire overhead on copying the stack doesn’t bother anyone - you’re slow or fast — it doesn't matter at all. Yes, if you use it for asynchronous programming. With us on Korutin in Kotlin, this is remarkably scaled, as shown in the prototype Project Loom.

    Another difference is that since we in Kotlin are forced to do this in bytecode, we have such an interesting side effect. On the one hand, it seems to be unfortunate, but on the other - on the contrary. It consists in the following: it is impossible to put down an arbitrary function. You need functions that can fall asleep, mark with the suspend modifier - clearly mark that the function can pause and wait for something, that it is long. On the one hand, you don’t need it in Loom, because runtime can put anything to sleep. Alibaba’s solution is the same - you can remove a stack from any thread. Or in Go - everything can be zassependit there, any code can fall asleep. Flood another gorutin and do. On the one hand, this approach is very similar to programming with threads. You kind of program as before, only now threads are called faybers and have become very cheap. If you carefully look at the presentation of the same Loom, it turns out that the faders and threads are different things after all. How to make the old code that is written with threads straightcompletely out of the box wound up on Fiber - is not clear, and they have come out - no one knows. The problems begin there: what to do with the deadlocks, what to do with the code that is optimized for thread locals, again, some local hashes have their own or, with thread ID, they do some cleverly performance optimization. And in Go, the same problem - when hard thread thread IDs don't expose, writing some kind of high performance algorithm becomes nontrivial.


    Is there no such thing in Kotlin?


    In Kotlin, we are not trying to pretend that thread and fayber are one and the same. We don’t even try to run the old code, we don’t have such a task in principle. We say: “Sorry, since we are not runtime, we cannot arbitrarily take the old java code and start switching something there”. And we will not even try. We have another task. We say that we have a language feature that functions are falling asleep, you can write asynchronous code with them, and this is a new language feature. And from this problem ("how to run the old code"), we thus completely distance ourselves, we say: "Here is the new code, good, Orthodox, it can be put to sleep." To some extent, this makes life easier, because you don’t need to float your head, or people, and what happens if some old govnokod who didn’t know that they are going to run it on the computers, they will suddenly launch them.

    We have no old code in our model, only a new one, which is initially prepared for the fact that today it is on one thread, tomorrow on another, and if, for example, it needs to know what thread it is, it will know it. Yes, we need thread local, but he can recognize them. However, he must be prepared for the fact that today thread locals are one, and tomorrow - others. If he wants these locales to travel with him, there is another mechanism for this, a corundum context, where he can store his things, which will travel along with the coruntine from thread to thread. This, in a sense, makes life easier for us, because we are not trying to maintain the old code.


    On the other hand, we force a person to clearly think about his API, to say: here I am writing a function on Kotlin with Korutins. If earlier I look at some method in my code, getWell , it is not clear, this method works quickly and returns immediately or goes to the network and can work for an hour - I can only read the documentation and understand how quickly it will work. Or maybe now it works fast, and tomorrow programmer Vasya Pupkin will come and make it so that he now goes to the network. With Kotlin-Korutin we give a language-guaranteed mechanism with the suspend modifier. When I myself work with Korutin, I look at some function, if I do not see the suspend modifier, it means that it works quickly, it does everything locally. There is a suspend modifier, which means that this function is somehow asynchronous, it will go on the network for a long time. And it helps to do a self-documenting API, so that we can immediately see what awaits us. This helps to immediately avoid stupid mistakes when I forgot somewhere and somewhere in the code I caused something long without knowing it.

    In practice, this turns out to be very good. This is the need to explicitly mark these sleeping functions. In Go, for example, this is not, I am not obliged to mark anything there. It turns out that this side effect of our implementation (which should be marked with the suspend modifier) ​​helps you to make the architecture correctly, helps you control that you will not cause some random wildly long asynchronous game in the place where you initially expected everything to happen quickly.


    But there are some things that are difficult to forbid, for example, some kind of network IO, file.


    No, network IO just ban quite easily. Here file IO - difficult. But here’s another subtle point: for most applications, file IO is a fast thing, and therefore it’s perfectly normal that it works synchronously. A very rare application works so much with IO that it becomes a problem that it takes so much time. And here we give a person the opportunity to choose: you can directly make an IO file with us and not bathe, because it will block what is happening (because usually it is fast). But if it’s specifically in your case, it’s just some kind of very long calculation, which is not asynchronous, but it’s just a lot of CPU time, and you don’t want to block any of your other thread pools, we provide a simple clear mechanism: you start a separate thread pool for their heavy calculations, and insteadfun computeSomething () , and write in the documentation "Dudes, neatly, this function can work for a very long time, so attention - do not use it anywhere, do not use it in the UI", we offer a simpler mechanism. You simply write this function as suspend fun computeSomething () , and to implement it you use the special library function withContext , which transfers the calculation to the special thread pool you specified. This is very convenient: the user does not need to float the brain anymore: he immediately sees suspend, knows that this call does not block his call, and he can quite easily call it from the UI thread, and so on.


    It will switch to the desired flow inside, and its flow will not be blocked. This is the correct separation of concern: the user does not soar, as it is implemented, and the one who implements can be thrown right into the pool to which it is needed, and the computational resources in the application are properly distributed. In practice, this is very convenient in terms of programming style. It is necessary to write less documentation, the compiler will check and correct more.


    I think how safe it is. Can someone break the thread pool or break into other people's data?


    Naturally, everything is possible. From the curves of the hands is hard to protect. It is clear that no matter how much we write in the compiler any type systems and checks, everything can always be broken. The question is that the compiler should help write the correct code. Unfortunately, the dream to forbid writing bad code is utopian. We specifically do not include any features in the language. In Kotlin, there are not any things from Java, if it is known about them that they are mainly used for inappropriate purposes and the code with them is basically bad. But any good feature that exists in Kotlin can be misused in a variety of ways. There are no options, unfortunately. Language can be abused differently. From the curves of the hands do not protect in any way.


    I learned from Kotlin learners what interesting question you can ask. They gave up and said that you are very cunning and leave their questions flexibly.


    What questions?


    For example, one question survived two people: why are there no raw types in Kotlin? Without generics.


    Because you can always write an asterisk.


    Will it be compatible with Java?


    Yes.


    That is, you have some kind of java method that requires something without a generic. List, for example.


    If there is such a Java method without a generic, you can transfer any List there. You can pass a list with an asterisk, you can with a string. Kotlin will allow you to transfer any game to the java method. If he returns the raw List to you, then in Kotlin you will get a certain platform type, which you can cast, for example, to the List with an asterisk. Because the raw type, in fact, in Java is not made from a good life, but to make it easier to migrate. There was Java, in which there were no generics, now there are generics, and so that people do not suffer, so that they do not need to affix these corner brackets throughout the code, this special feature, raw type, was made. When Kotlin was done, there was no such problem - there was no old code in which generics are not indicated. There is only a new code in which all types are generics. Therefore, the problem of migration from the old code without generics to the new code with generics - it does not exist, and there is no point in doing such a feature in the language, like raw types. She Kotlin is not needed, since there is no migration story.


    How does the casting platform type work for Kotlinovsky?


    Platform in Kotlin are considered flexible. This is easier to consider using the example of nullable types. Here you have Java code that returns a String. In Kotlin, it is not clear, where String or nullable String are two different types. And we do not know which String is returned from the javov method - nullable or non-nullable. Therefore, Kotlin believes that he can be both such and that. And allows you to assign it both in the String and in the nullable String. It’s the same here, when you get some kind of weakly typed game from Java, you can always point to Kotlin just a more specific and correct type.


    And if you indicated wrong?


    If you have indicated something completely inappropriate, then your compiler will naturally curse because it has to be suitable. Flexible doesn't mean anything, it's not dynamic. Flexible indicates the range - what Java has now returned, then you can assign both to String and to nullable String, but not to int.


    There is still some direct enumeration of the possible, and it matches there.


    The same with raw types, a similar mechanism, but a bit more complicated. Same with collections. In Kotlin collections are divided into read only and mutable. You have a List and MutableList. If Java returns a List to you, then FIG will understand what the Java programmer meant, you can mutate it or not, therefore you can assign it to List on the Kotlin-side or in MutableList. Kotlin is more strongly typed than Java. Accordingly, when you get something from Java, you should specify a more specific type and vice versa. It works out of the box in the opposite direction, since the Java method accepts less typed things, you can transfer any suitable Kotlin thing to it. Again, for example, the List method accepts, for example, we do not know which one, so you can pass the MutableList and the usual List there. And if you don’t transfer the List,


    And when javovskie are used any or what, what is the correct approach? It is necessary to wrap in some Kotlinov's vrappers?


    No, nothing needs to be wrapped. Kotlin zadizaynen so that javovskie library was easy to use. It just works. Most Java libraries simply work with Kotlin without any problems. And if there are still nullability-annotations registered, then Kotlin immediately sees if the result is nullable or not. But convenience depends on the design of the library, of course. Kotlin, for example, has a special syntax, when it is convenient to transfer the last lambda behind round brackets. For example, in Java libs that have the same order of arguments, it is clear that some predicate is taken as the last argument. In Kotlin, you can use it without any special adapters, you can simply use Kotlin's beautifully. You take some JavaFx, and without any additional adapters the code on Kotlin turns out more beautiful, than if you used JavaFx in Java, it is more convenient, more pleasant to watch it. It is clear that you can still write yourself some adapters, and it will be even better. But even without them, java libs are nice to use. Any lib becomes steeper and more convenient if you just start using it from Kotlin, just by using Kotlin.


    Your voice has already changed, so emotionally you describe everything.


    Of course. I just saw it many times, you just enjoy programming. We hope for the same with Kotlin Native. The idea is the same: Kotlin is more pleasant as a language, and we are trying to make as seamless as possible interop with any C-shny ecosystem, just to give people the opportunity to use their existing from a more pleasant language, without any barriers.


    By the way, after all, when switching to Native, should there not be a change in the meaning of language constructs?


    Of course, with us, even if you look at Kotlin JavaScript, some constructions work a little differently. We do not aim to achieve “Write once, run anywhere”, it is not worth such a goal that it is absolutely identical. Our task is a bit different: we want a certain subset of the language, like Common Kotlin or Portable Kotlin, in which you will write, and it will work from everywhere. It is clear that you can get into some platform-specific things, and their behavior will be appropriate, but this is normal. If you write under one platform, and you don’t care, and under several platforms you’ll just bypass things. And we do not specifically fix many things to preserve performance.

    On the JVM, we have a performance like Java, on JS our performance is almost the same as that of JS, on Native native performance. The task, in the first place, in spite of this portability, is to give the native platform high-performance code, and not to write another virtual machine. Many people try to transpose some java into the same JS, an attempt to completely emulate java. This attempt leads to a huge overhead-performance. Some trivial silly things: you take a double, convert to String. And on JVM-Mr. Kotlin, the number 0 will turn into the string "0.0", and on the native JS there will be just zero. Different behavior. It would be possible to fix this on JS, but then all conversions of numbers to strings would become much more inhibited, because it would be hung with additional checks - who needs it? Let it be a little difference, but native performance. We do not have any special brake function that converts numbers to strings; we just have a native JS-conversion. There are many such examples, where we specifically decide to make different behaviors from performance considerations. But where it is not critical. Still, the semantics of the basic constructs of the language — classes, inheritance, calls, and so on — all work the same way. We have an example of huge projects, both own and external, in which a lot of code is written on Kotlin, it compiles and works under JVM, JS, Native - and all this works fine, even though there is a bit of behavior somewhere is different. All tests pass. where we specifically decide to make different behaviors from performance considerations. But where it is not critical. Still, the semantics of the basic constructs of the language — classes, inheritance, calls, and so on — all work the same way. We have an example of huge projects, both own and external, in which a lot of code is written on Kotlin, it compiles and works under JVM, JS, Native - and all this works fine, even though there is a bit of behavior somewhere is different. All tests pass. where we specifically decide to make different behaviors from performance considerations. But where it is not critical. Still, the semantics of the basic constructs of the language — classes, inheritance, calls, and so on — all work the same way. We have an example of huge projects, both own and external, in which a lot of code is written on Kotlin, it compiles and works under JVM, JS, Native - and all this works fine, even though there is a bit of behavior somewhere is different. All tests pass. Native - and all this works fine, even though somewhere the behavior is slightly different. All tests pass. Native - and all this works fine, even though somewhere the behavior is slightly different. All tests pass.


    Do the corutines work on all platforms?


    Yes. This is a feature of the language, which doesn't care under which platform you run it.


    That is, the entire unwinding of the stack, that's all ...


    Yes, this is all a purely compiler feature. We do not need support from the platform, that's the trick. Unlike the Loom project and so on. We do not do this with some kind of hack in the JVM. This is a compiler feature, so we can do the same for any platform.


    And if you take the Kotlin code and try to fix it, for example, in Java?


    Then you will see there all this game that the compiler issued. But you have a beautiful code at the entrance. In the sense - but you wrote a beautiful code . This is the task of the compiler to make something from this that will work. In Kotlin, there are many high-level constructions, which then turn into some kind of low-level blizzard. For example, you write for (i in 0..10) , and it unfolds in a for loop (int i = first and other game. But it's nice to write, so what's the difference how it compiles there. It works. Quickly, because it unfolds into the corresponding native constructs.


    Has anyone compared the same programs on different platforms?


    No, and what's more ... despite the goal to preserve performance, the platforms are initially incomparable. They have different tasks. What is the point of comparing JVM and JS.


    And what's the point of writing on a server on Node.js?


    So I understand why! Not for performance. People write in order to reuse their JS programmers. Why learn a new language, hire new programmers, if JS-programmers quietly write the backend. We want to give such a story with a better, more typed language. If you know how to program in Kotlin, then you wrote a business logic once and then please - drive it on the Java backend, jog on the JS-frontend, drive in the native microservice or something - don't care. If the code is on Kotlin, it will be able to compile anywhere. This is Kotlin's goal.


    You had reports like "million quotes". Would you use Kotlin in your previous projects if it were invented much earlier?


    Of course. Everything that I said in those days can be done on Kotlin. On the JVM, this is simply a more convenient language than Java, compiled into the same bytecode. Therefore, it does not make much sense not to use it on the JVM. Is that your legacy, enterprise, and it is simply forbidden. Or if you make a library that must be used by clients that Kotlin cannot use. And if you write for yourself, there is no point not to write on Kotlin under the JVM. Baytkod is the same, and at the entrance - not only more convenient, but also more compact language. It is also more typed, protects against more errors. But it does not force you to write a very hard-typed game, - as always in the JVM you can tell the compiler "I know better than you." Mechanisms to bypass the compiler you have. But in normal practice, APIs on Kotlin are more documented, more stringent and more secure. The code turns out to be more reliable, rarely falls on exceptions. It is easier to read, less water in the code. Many pieces, when I would have to write boilerplaces in Java, are written in Kotlin in one or several lines. It is more pleasant to work with such code, it has less water and more essence that you wanted to express.


    This weekend Roman will be at the TechTrain festival with the report “Why do I need another programming language?” . About this festival, we recently wrote on Habré . Take a look, suddenly like it.

    Training and Olympiad


    Since you started talking about JS and learning, how difficult is it to retrain with Java on Kotlin?


    But with Java it is just very easy and there are no problems at all. We also have a book “Kotlin in Action”, and a website focused on Java programmers. By experience, a Java programmer needs to spend from two days to two weeks, and that's all, an excellent Kotlin programmer has come out of you. And it was not by chance that it turned out, this is “by design”. Initially, Kotlin’s design implies that Java programmers should easily switch to it. Bicycle did not invent. Andrei Breslav has a good report on the past of the JPoint , from which Kotlin borrowed. There is a slide on where different language constructs were born. It can be seen that 60-70% come from Java. It is called as in Java, so that it is easier, so that you do not need to learn something strongly new. These are big languages ​​like Java can afford it.

    They generally have such a design goal - this is what Gosling said that if we take something, we will definitely call it differently. Nothing is ever taken as-is. We are big people, we can afford, let people teach. In Kotlin, if you already know what a “class” is, this should be called a “class”. If you know what an “interface” is, it should be called an interface. People know the while loop - there is no point in renaming it. Although you can find 100,500 more good titles for it. But why? In addition, most of our training materials are designed for Java programmers. Even I did some reports, “Introduction to Kotlin”, and all this is intended for them, you only need to tell what are the main things in Kotlin that are new and interesting.


    The problem arises if you learn to program from scratch. We still do not have enough training material. Now we are working on a book that will be released this or next year, and it will be especially for beginners. In the future, the site will also be.


    For such newbies, what really, really, or for defectors from other languages?


    Yes, for absolutely newbies. We are also trying to cooperate with universities. On the path of retraining Java programmers, we have come very far. Android programmers, too - more than half, like the latest data. And all retrained without problems. A million programmers at least have already retrained, and there are no problems. But on learning from scratch - we are at a very early stage of the path.


    Are there any jokes that people find it hard to understand from scratch?


    They are the same as in other languages. It is difficult for people to understand nested loops, recursion, references. This is a known topic, no matter what language you are programming. Training a person from scratch is a kind of art, there are difficult issues that need to be adequately explained. But in this regard, Kotlin is very good. For example, we receive feedback from universities. If you take a basic programming course at some university and see what they are taught, it turns out that no one teaches classes right away. Usually they teach simple procedural things: how to write loops, how to write functions to call, and so on. Previously, many were taught in C ++, then rushed into Java, now in Python. But not every language is equally good. The same Java was once very popular, and so far many introductory courses are read in Java, but this is not the best language for an introductory programming course. To write a simple hellow world, you need to write a class, puiblic static void main ... And you teach not procedural programming, but procedural programming. In Java, to write anything, you need to declare a class. Why should a newbie soar brain?

    Kotlin in this regard is more suitable for learning: you open the file, you write your functions, almost like in Python, only with types. Compared to C ++, you can bet because C ++ is a very large language. This does not mean that the pros can not teach programmers, you can. But when they teach on the pros, they teach a very limited subset. They tell small chips, very carefully, so that the student does not take a step to the left and a step to the right. And Kotlin is a good typed language. If you want to teach a good untyped language, this is Python. I as the first programming language taught the daughter to the Python. In order not to clog her head types. When you don’t know how to program at all, you need to learn a lot. It does not happen that you immediately know everything. Need to gradually learn. Therefore, it is easier to first teach all imperative constructions - cycles, input, output, functions, procedures - and types to be put aside for the time being. The next language must be typed to deal with types.


    So you think typing is a useful thing?


    I do not just think that it is useful. This is a must have. Nobody writes documentation in their code, and even if they write, they are not manteynit and do not read. Therefore, without types, no development is scaled. Alone, you can still program in an untyped language, programs up to ten thousand lines at most. Ten thousand is already hard. And if I have a big project, a lot of developers, this is simply unsupported, nothing can be understood.


    And how do javascripters live?


    Well, how they live ... they finished the project, abandoned it, went to the next one. So they live. Most JS projects are very small. Did - and everything. There are big projects on JS, but they don’t live there, but suffer. And if someone tries to do a big project on JS, most likely it goes to type checkers, to Flow or TypeScript. Something big to support on JS is difficult precisely because of the absence of types. The same with Python. While this is some kind of template DSLki, everything is fine. You can start a huge project on Django if you don’t reinvent the wheel. You write dzhangovskie classics, using conventional mechanisms. When I talked about the complexity of the project in the lines, it is, of course, a hoax. The complexity is not determined by the lines of code. I can have a huge site on Django, where a huge number of lines of code, ten thousand and CRUD-pages. But since they are all equally smart, there is no business logic - it's all easy and understandable. But as soon as I start writing complex business logic, doing some sort of class hierarchy, modeling a complex domain, then in an untyped language, I will die very quickly. Very fast. And it will be impossible to support all this. This is the basis of the Kotlin philosophy, which is even more typed than Java, even more rigorous. This is the core belief in the Kotlin team that industrial-scale language must be strongly typed. even more stringent. This is the core belief in the Kotlin team that industrial-scale language must be strongly typed. even more stringent. This is the core belief in the Kotlin team that industrial-scale language must be strongly typed.


    Correctly I understand that if there is some big complex frontend, then even there Kotlin already makes sense?


    Of course! If the frontend is large and complex, it means that there are hardly any CRUD pages in it. Again, you need to distinguish: if you have a large and complex website with many pages, and all the pages are the same, and there is no logic - views, then this is one. But if this is a large complex web application, it has a lot of complex logic - of course, you need a typed language. This explains why TypeScript and Flow are gaining popularity - these are typed pieces on top of JS.


    There is another point about Kotlin that Kotlin for JS cannot defeat TypeScript just like that, one on one. If you compare the development of web on TS and Kotlin / JS, naturally, TS will win, because it is designed for the JS-ecosystem, it is created for it directly. But Kotlin / JS will win if you need to fumble this code. You can compile to frontend and backend.


    And there will be all sorts of sharpening, about which you spoke - like converting double ...


    Yes, but in practice it’s all pretty minor differences. We very carefully think about where we can allow different behavior to be, and where not.


    Once you have been associated with Olympiad programming.


    I am still connected.


    And what are you doing?


    I spend olympiads :-) And I participate myself, but rarely.


    I just see that Java is sometimes available at olympiads as one of the main languages.


    Now it is almost always available. She appeared about fifteen years ago. Java and C ++ are two standard languages ​​that all support, and then variations, depending on the competition.


    Is it harder to win in Java, are there any hidden overheads?


    Depends on the competition. In a normal competition - the same, if it has more tasks for the idea and the correct algorithm. But there is some kind of game, when tasks imply non-asymptotic optimization, where you need to optimize everything to the tact - there, of course, Java will be hard, you have to try a lot. Plus there is a very short test time. Roughly speaking, if you have a time limit of a few seconds, then HotSpot warms up for a second on a small code and doesn't care. And if you have a limit on everything - a second, then in Java you can lose simply due to the fact that while HotSpot is warming up and compiling - already a second has passed.

    Yes, there are wild competitions, where Java is hard. But normal competitions (popular, supported by good people) - they try to do the tasks and the environment in such a way that the same chances are available in Java and on the pluses. And the reasons are clear: although Java does not grow in education, it does not decrease much anywhere. Somewhere, some universities refused to learn Java and switched to Python - and because of this, including now many competitions have learned Python. This is such a stable third language supported. Competitions, mainly student. There are professional competitions, and large companies are doing something like the Facebook Hacker Cup, where everyone can participate, but still, the main theme in sports programming is school and student. In school and student years, people will constantly perform and train. But after graduation from university, after going to work - very few people will continue to participate. Therefore, the choice of languages ​​is determined by what is used in education. If they teach pros, Java and python, then they will be in competitions. For many Java programmers - the first language, respectively, all the competitions are trying to support Java. For the sake of competition to learn C + + - game. It is for system programming, low-level programming, you do not need to have a million C ++ programmers, it’s completely pointless.


    And how do you get the idea to add Kotlin to the list of standard languages?


    Well, actually, we are actively promoting this idea. There is the ICPC, which passes annually, gathers hundreds of thousands of participants around the world, more than a hundred teams go to the final. In ICPC Kotlin is supported. Now there is a list of languages ​​like this: C / C ++, Java, Python and Kotlin. But so far, of course, nobody really writes on it, because of the following problem: penetration into education at a very early stage. The student competitions use the languages ​​that students learn.


    And somewhere already teach Kotlin?


    Somewhere exactly taught. For example, in the St. Petersburg Polytechnic. But we are still at a very early stage, at the “step 0” of this process.


    Are there any fatal flaws?


    No, for primary education, Kotlin is better than other languages. Just education - conservative. People have a ready-made program, textbooks. No one likes change. Why does a professor who teaches programming in the first year of students change the language, what is the bonus? This may be reviewed every ten years.


    The bonus, for example, is that the person who leaves there will be more adapted to reality.


    Not. Because it is not so important what language you learned first. A professional programmer in his life studies a dozen languages ​​and uses about three languages ​​actively. Plus, all this is constantly changing. What you learn to program first is not so important. It is important what language baggage you have for graduating from a university - this is another topic, this is important. And here we are faced with problems in conservative markets that are focused on authority. For example, in China there is a problem that becomes clear after talking with the guys from there. You take some large office in which there are a lot of programmers, you ask - why don't you use Kotlin? And because now, the children did not teach Kotlin in the university, and they don’t want to learn anything new, but why should they?


    Are we wrong?


    It is everywhere like that, just on a different scale. Different cultures in different ways. There are cultures in which both the guru said or the teacher said, and you will do so. Somewhere people are more independent, more inclined to experiment, innovations. Somewhere people will go and study everything themselves. Somewhere they won't lift a finger and will do exactly what they have been taught. There are more Kotlin implementations in Russia, but this is also because we initially come from here, speak more at conferences and so on.


    This is my generation of programmers were enthusiasts. I grew up when those who liked it were programming, they studied everything on their own, because there was nothing. And now this is a massive thing that is being taught. Take a modern programmer, most do it not because they love, but because they have learned this and now they pay a lot of money. Accordingly, such people will not learn the technology that has just been released. Why should they?


    Because you will earn a lot of money using cool features of this technology.


    Of course not! On Kotlin you rather get more pleasure.


    There are concrete things that really have a business value - we talked about re-use between the front and back ...


    Not everyone needs it. On the other hand, and fun too. Not everyone enjoys their work at all. They get paid money - they work, what difference does it make if they get pleasure or not. The work day is over - they closed and forgot about it, and started to do other things.


    It is somehow very sad, if not terrible.


    This is a fact of life, unfortunately. No matter how terrible it is. And such people, of course, do not care. Kotlin, not Kotlin.


    As far as I understand, very many people work in JetBrains because they like to work.


    JetBrains in this regard is a non-representative sample, naturally. Specially selected people, motivated, who really like this thing.


    Our time is slowly coming to an end, so the question is: can you pass on something to our readers on Habré? Any farewell, any revelation?


    I can convey heartfelt greetings :-) And I will not say any revelations, what kind of revelation can there be? The only conclusion that can be drawn from our conversation is that the one who gets pleasure from work is happy. I read a few blogs of good people who programmed on Java, just worked without getting any pleasure. And then for some reason they became curious, life made, they tried Kotlin, and unexpectedly discovered that you can enjoy working. What can love what you do. What can love programming language. And not just use, unemotional, as a kind of tool. Of course, the language is a kind of tool, but you can treat it indirectly, but you can love it. This is a different attitude, including a different attitude to work creates.

    A lot of people have warm feelings for Kotlin, comparable to love, precisely because Kotlin is a pleasure to program, especially after Java. Maybe not only after Java. Probably, there are no languages ​​in which it is so pleasant (just such a word) to program. There are languages ​​with greater functionality, with stronger features, there are languages ​​with a more strict type system, there are languages ​​where everything is pure, there is everything where it is the other way around - unsafe. Take any measurement, and find the languages ​​that are in this property cooler Kotlin. But Kotlin has such a balance that it’s not without purpose that it is on StackOverflow in this year’s survey.It turned out to be the second in the top of most loved languages. The first, it seems, was Rust. But Rust is not a competitor, because Rust is a system programming language. We do not climb into this niche. It doesn’t hurt that Rust overtook Kotlin in this respect. We are fighting for Kotlin to become the main language for application programming, in which it is pleasant to solve applied problems. We don’t and will never have some Rust features, because an application programmer simply doesn’t need them. He should not manually manage the memory or think about the intricacies of ownership, the application programmer must solve business problems. He has to transform his domain into code. And this should be as direct a conversion as possible without any factors interfering with it. We are trying to eliminate these interfering factors. To make your business problem as straight as possible,


    Well, this is a somewhat unfair competition - all these languages ​​like Java were invented many years ago, and you - just that.


    Naturally, Kotlin takes into account the experience of predecessors. Like any modern language. This is progress - when something new is created taking into account old flaws. Not for nothing are nullable types made in Kotlin. Well, go far, take any enterprise, go to any large office, look at their crash logs, and see that the most frequent exception is NullPointerException. This is a well-known fact, and if you make a new language, you need to solve it. Therefore, we pay a lot of attention in the language nullability. And so on. If you do not design a language in an abstract way, not as an academic exercise, but you try to solve the problems of people that they often encounter, then the language is good. Why love him? Because he solves their problems.


    Also popular now: