Why Kotlin is my next programming language (2015)
medium.com
medium.com
Like a waiter advising, "Choose the chicken parm. It doesn't have any bones, all the salmonella has been cooked out, and it doesn't have any bad flavor."
If I'm going to be successfully pitched a programming language, I will need to see its power of expression or be shown how it solves some problems that other languages don't address well. Some "special sauce."
No offense intended ... that's just my quick take.
I think that is wrong approach. Kotlin has nothing special or innovative, everything was already here. But it is well balanced and industrial strength (something like java). It is simply good workhorse for most tasks. It is excellent replacement for java, that is all.
(I don't think Kotlin is such a language - I think Ceylon might be. I work in Scala at the moment)
* Ceylon has actually listened to the lessons of Scala tuples and built theirs the way ours should have been all along (HLists), making them much easier to abstract over. (NB not actually an issue in Scala in practice - you import Shapeless and then everything works the way it should - but it's nicer to have the right thing by default, as will hopefully be the case in Scala 3.x)
* Ceylon has higher-kinded type support done right - multiple parameter lists to avoid Scala's unification issues that lead to the use of "type lambdas" (hopefully fixed in Scala 2.12).
Kotlin simply doesn't support higher-kinded types; combined with the lack of union types this means magical annotations with bytecode manipulation where suddenly the code you wrote isn't the code that runs, because just like Java that's the only way to do a lot of things in Kotlin. Async is a special case with language-level dedicated support code. Error handling is done solely through unchecked exceptions which is fine for system failures but not a good way to handle "expected" failures like input validation.
In the end I did choose Kotlin. My reasons included:
* support in IDEA
* focus on java interoperability
* nice interop with android
but the main thing probably was, that I trust JetBrains that they will support Kotlin in the long term, while I don't think RedHat has any projects depending on the language.
So, why would you choose Ceylon?
This succinctly describes many aspects of Kotlin.
Kotlin is getting rapid adoption in the Android community and is quickly getting the same status as Swift has in the iOS world.
The main reasons for the rapid adoption are:
- It's designed to easily integrate into existing Java codebases. This means that starting to use Kotlin is pretty much a case of adding two Gradle dependencies and source files into `src/kotlin`. Interop with Java is painless and doesn't require any special boxing as opposed to some other languages.
- It's standard library is small (~700KB), which is a stark contrast to Scala and some other JVM languages, which pretty much demand usage of ProGuard while developing due to large method count.
- It's performance characteristics are close to Java and doesn't cause catastrophic GC collection issues like some Clojure code does.
- It has pretty much all the features expected from a modern language (nullability, const values, concise syntax) while still keeping code very readable for people who already know Java. The adoption in our Java codebase has thus been rather painless, since code doesn't do any additional magic you wouldn't expect.
- It compiles code to Java bytecode which runs on Java 6 JVM, which is critical for Android.
- It has first-party support in IntelliJ IDEs, which includes Android Studio itself. The IDE experience is significantly better than Scala or Clojure one and almost on par with Java.
So in short, we got a modern language, which is easy to transition to from Java 6, gives seamless interoperability with existing Java code (you can just start writing Kotlin classes in your Java code base), doesn't add overhead to your Android application and doesn't behave strangely performance-wise. There are still some warts to fix (mostly related to static checkers), but Kotlin has been a huge win for Android world.
What's keeping Swift itself from eventually becoming the preferred language for Android as well?
And the fact that there's no standard library outside the Apple world for the language. Adoption of Swift makes pretty much no sense, technologically or politically.
As a C/C++ alternative for native development on Android... possibly.
This will be in great part decided by
1) How frustrated native Android developers currently are with C/C++ (I don't have the feeling they are much) and
2) How much resources Apple will dedicate to make Swift viable on Android (hard to imagine they would be that interested helping out the #1 player in that space while their #2 spot is shrinking on a daily basis).
A Scala Hello World is around 30 kB, it can get more as you keep using more of the standard library, but to be realistic, it's around a few hundred kBs.
Not sure what's the big deal with ProGuard it's just a deployment detail. Compilation seems to be faster with SBT and ProGuard than Java/Kotlin/... without ProGuard.
EDIT: On the other hand Java 6 byte code might run just fine under I.E JRE 8?
I found it to be more verbose than a typical modern scripting language. Maybe it's the result of choosing the least of the evils for what it's trying to accomplish.
The other drawback: the documentation. Kotlin's reference documentation (looking up how to properly use a call) does not have any examples. I'm not even talking about full compilable examples - although that would be nice, it doesn't even have one-liner examples. FWIW, I was trying to look up how to use a comparator to sort a MutableArray<Int,Int>.
I agree about the documentation – I think it's one of the biggest reasons the language has seen such little adoption given its benefits.
I couldn't even find how to integrate Kotlin files into a Java project without using IntelliJ. Kotlin is developed by Jetbrains, so of course they're used to IDE-driven-development, and have a financial stake in people using their products for development. But coming from scripting languages, this sort of documentation gap was a real turn-off for me.
I would suggest (and I'm not trying to bag on you with this) that this concern is more your unfamiliarity with the JVM than a failure of Kotlin, which is generally targeting Java and Scala developers. Kotlin operates pretty idiomatically in the Java universe and, as an experienced JVM developer who's comfortable with all of Maven, Gradle, and SBT, I dropped Kotlin into a Maven project, side-by-side with Java, with a cursory glance at the documentation--"oh, it's another pre-compile-step thing". (Which I then consume via IntelliJ, because IntelliJ imports Maven projects nicely, but Maven allows others to use their IDE of choice.)
The pre-compile-step thing sucks, I'll be the first to say that, and it's a problem with multi-language, multi-compiler projects that none of the major build systems on the JVM really handle admirably. I prefer to use multi-module Maven projects and separate out Java and Kotlin--or Scala, for that matter--code into separate ones. But that's a different beast entirely from the initial bootstrap when learning.
Correct!
> a problem with multi-language, multi-compiler projects that none of the major build systems on the JVM really handle admirably
A bummer to hear – though I'm glad it's not just me. I tried using Kotlin with the Play Framework and did not have a great time. The hot-reloading features of Play didn't work with Kotlin at all, even with my attempts to `touch` a Java file whenever my Kotlin file changed (presumably they're recompiling more intelligently than I was).
Perhaps having SomeController.java and SomeController.kt in parallel, where the former imports the latter, and receives a `touch` or similar whenever the Kotlin file changes, might work? Or would you recon such a project to be a fool's errand?
Btw, the whole kotlinlang.org is OSS, and you can correct things you don't
Depending on where you are in the security vs efficiency spectrum, you may opt to ignore those assertions in production.
Writing specific tests for that looks very inefficient to me but maybe I am missing something.
If some function A calls function B with a wrong type, the problem is with function A. So basically, there should be only type tests after IO functions (probably after parsing), the rest can be assertions.
At some point you have to assume something is there and correct (e.g., you don't write tests to check whether the tests are there, also you assume the testing tools work, ...).
In static languages you also assume the programmer set the right type for the function argument, so you might as well assume to have an assertion in the critical code of the functional languages.
If you excel at compositional design then this may work OK but a lot of code bases I have worked on just need a good ol' refactor to sort the mess out. And then the "there and correct" part could fail due to human error, or the new person not knowing the old assumptions etc. The asserts are a step in the right direction in documenting the assumptions though. Types go one level better by both documenting the interface, and enforcing that contract at compile time.
* true as in all possible inputs and outputs rather than merely all code paths
Your comment just solved the problem by ignoring the latter, not much of a contribution to say the least.
I agree that writing specific tests for that is very inefficient, and that few people (myself included) actually do it. I just also think the fact that people don't really write tests for a (anecdotally) common cause of bugs, and instead wait to see them in their production logs, is an anti-pattern, rather than a positive thing.
I want the function to fail when it is passed the wrong arguments, but I don't really care about how exactly it fails. If the wrong types get passed to a function, I'm already screwed and there's no way to do the right thing at that point. I only care that I get enough information to debug what happened.
In pretty much any other case, I want to function return some precise value or do some precise action. These are situations that the code will encounter during normal execution, and so I do care about what exactly it does.
For the tests the check types of values, that's just a dumb test that you shouldn't write regardless of the language.
Then for rest of the post, he talks about having nicely-defined tests which is orthogonal to whether or not your types are static.
The thing is, almost all the tests you'd write in a dynamic language end up being something you can encode into the types of values.
Can you actually give an example of a test that would be realistically written in a dynamic language that would be something encoded into the types of values?
There is a definition for the schema to a fruit table.
Fruit: {
list_id: 32
}
The list_id indicates that this isn't a real table, but is actually stored in the list_options table. So my code has to generate a different query then for a normal table.The actual options are populated from a list:
const LIST_OPTIONS = [
[32, "Blueberry", 1],
[32, "Apple", 2],
[32, "Orange", 45],
[45, "Nope", 1]
]
These get inserted into the database. Note that the first column is the list_id from the schema.And for the actual test:
This actual sends the request to be processed.
let response = await processRequest({
type: 'QUERY',
table: 'Fruit',
})
Then I assert that the respone is exactly what I thought it would be: deepStrictEqual(response, {
status: 'OK',
records: [{
id: "Blueberry",
name: "Blueberry",
position: 1
}, {
id: "Apple",
name: "Apple",
position: 2
}, {
id: "Orange",
name: "Orange",
position: 45
}]
I would have written pretty much the exact same test if it were a statically typed language.That aside, what pieces could actually go wrong in a statically typed language? You can't typo field names or the like. You could typo the names, but I don't believe typing them into the computer twice adds value - better to check them once in code review. People aren't going to be editing this code in a way that could lead to getting the names wrong.
You couldn't go down the wrong code path and end up with the "normal table" query, because having list_id instead of something else is part of the type. You couldn't pass some other number as the list id, because list ID is a typed thing that is different from all other IDs, and in any case where would an outside number come from? And you're definitely going to return a response that's formatted with a record list, because that's part of the type of the method. (You might need to test the JSON <-> String piece, but that's generic, so you only need an O(1) test for that, you don't have to test every JSON endpoint. In practice you're likely using an existing well-tested library. Similar reasoning applies to the database querying part). Assuming you have warn-for-unused-parameters enabled, you couldn't forget to apply the criterion and just return everything in the list.
So yeah, assuming this was for part of an existing system where I'd already tested generic facilities like database access and JSON serialization, I wouldn't feel the need to write this test at all.
But this is the generic facility for database access. This is just an additional special case it has to handle. Does that change your perspective on whether you would write a test for it?
> That aside, what pieces could actually go wrong in a statically typed language?
Well, I could type the SQL wrong, but let's assume we are working in a sufficiently awesome statically typed language that would catch that kind of error.
I could filter on the wrong column, with the wrong operator, with the wrong value, on the wrong table. I could decode the name column using the wrong encoding. I could return multiple rows per option. I could do a huge number of other things that I couldn't think of. These may not be really likely to be mistakes I'd make (this is a pretty simple task), but several refactorings down the line, I can easily see an issue being introduced.
At the end of the day, even in a statically typed language where much of the functionality would be verified by the compiler, I'd still like to have a test on this.
> Ok, good example on some levels, though it's doing a lot of interfacing with untyped parts
Hmm... the fact that it deals with the boundary of the system and the fact that it deals only with converting data from one format to another might render it a poor sample (i.e. there's not really much interesting logic). I can come up with another if you are interested.
Presumably it would be using a lower layer - or more likely an existing library - for doing the actual query though?
> I could filter on the wrong column,
Not if you've got a typed representation of which column's which
> with the wrong operator,
Not if equality is the only operator available. This is one of my biggest reasons for using wrapper types around IDs - you shouldn't treat IDs as integers, because the idea of adding or multiplying or <=ing an ID makes no sense.
> with the wrong value,
How? You have to use the passed ID for something, and it can't do anything else.
> on the wrong table.
So make the table part of the type. A list ID is a different thing from a user ID, they shouldn't be compatible.
> I could decode the name column using the wrong encoding.
Encoding should absolutely be handled with types.
> I could return multiple rows per option.
Hmm, maybe. But I can't see how you'd do that by accident.
> At the end of the day, even in a statically typed language where much of the functionality would be verified by the compiler, I'd still like to have a test on this.
I started out thinking the same thing (I moved from Java/Python to Scala). I've gradually reduced the amount of tests I write over four years as I've found them to not add value. I was as surprised as anyone, and even privately entertained the thought that maybe I was some kind of super-programmer who was smarter than all those people who needed tests, but that month or two of trying to do stuff in Django made it very clear that it wasn't me, it was the language.
> Hmm... the fact that it deals with the boundary of the system and the fact that it deals only with converting data from one format to another might render it a poor sample (i.e. there's not really much interesting logic). I can come up with another if you are interested.
Yeah, happy to if you're interested. It's a useful exercise in thinking it through for myself as much as anything.
Ah, Scala. I could be prepared to believe that this is true for Scala (and similarly advanced typed systems). It is when people claim they write fewer tests in java than in python that I found it really dubious.
> Yeah, happy to if you're interested. It's a useful exercise in thinking it through for myself as much as anything.
Ok here's another test:
These are action objects, they represent a sequence of user actions on a JobExtra.
const actions = [
JobExtra.actions.load(undefined),
JobExtra.actions.field('changeAmount', Money.actions.set(new Decimal("12.45"))),
JobExtra.actions.field('certifiedForemanRelated', Checkbox.actions.set(true)),
JobExtra.actions.field('appliedPercentage', Percentage.actions.set(new Decimal("4.5")))
]
I construct the final state by reducing across all those actions const state = _.reduce(actions, (state, action) => JobExtra.reducer(state, action), undefined)
I verify that the job extra is considered valid afterwards. strictEqual(true, isJobExtraValid(state))
To be considered valid:1. The changeAmount must be set to non-zero 2. The certifiedFormanRelated must be false or the appliedPercentage must be true
But, if the user modifies the appliedPercentage, the certifiedFormanRelated should be automatically set to true.
So this, and a number of related tests verify that under different sequences of actions I end up the result I expected.
Is there a way to push this into the type system?
For 1., you could have a non-zero number type, or you could settle for a check in the JobExtra constructor. For 2., it sounds like this is a coproduct situation - a JobExtra is either certifiedFormanRelated or has an appliedPercentage. Scala doesn't quite have native support for coproducts the way it does for tuples, but you could represent it with a sealed class hierarchy:
sealed trait ForemanOrPercentage
case class ForemanRelated() extends ForemanOrPercentage
case class AppliedPercentage(value: Decimal) extends ForemanOrPercentage
or being a bit lazier you could just use an Option[Decimal] and say that if it's Some it's the applied percentage and if it's None then it's certified foreman related.In Java there isn't a "sealed" keyword, but you can emulate it with the visitor pattern - you'd define a ForemanOrPercentageVisitor and only ever operate on ForemanOrPercentages via the visitor. That way if someone creates their own subtype of ForemanOrPercentage it still has to behave like one or the other, because they still have to implement visit().
Since the user input modifies this object, the user can put the object into an invalid state. In fact, when the object is first created it is in an invalid state. So I can't simply define my types so that invalid state is impossible.
That's very interesting, and shows how types can go much further then what we see in languages like Java. I'll have to try out one of these languages some day and see how well it works in practice.
No, I don't think so. I'll write a test that uses the library. If the library returns null when I don't expect it, it'll go into my code an cause an exception to tbe thrown. I'm not deliberately testing for nulls, I'm testing generally that my code does what I think it does.
The kind of library function that returns null doesn't usually return it on the "happy path", it usually returns null for some weird condition you haven't thought of. I mean, if it's a function that returns null often or that you'd expect to sometimes return null, you'll wrap up the return value in an option straight away even without having written a test. The kind of library function that causes you to get exceptions in production is the kind that returns null in some weird corner case - but unless you think of the weird corner case, you wouldn't hit it in a test either.
If I was using a library with some complex stateful interface I might write tests for the interaction with that (I'd probably put a facade on it, keeping it separate from the business logic, and the facade would have unit tests) - but I'd try to avoid using such a library. And I'll always have a few high-level end-to-end tests (not really "unit" tests) as a basic "does it work at all", because that kind of mistake is easy to make. But the bread-and-butter unit tests that I wrote when I worked in Python just don't seem valuable or necessary.
Honestly, I can't say how it would work if I was using a java code base that consistently applied these kinds of ideas. You may be right, but at this point I have hard time believing.
It's a lot harder to design a static type system that's both expressive enough to be pleasant to use and strict enough to be useful. But we're getting there in modern languages like Rust, Kotlin, Swift etc.
That's the reason one should use build tools, be it Ant, Maven, or Gradle. The process of setting them up without an IDE is narrowly described in the docs https://kotlinlang.org/docs/tutorials/build-tools.html
The way to go is to use auto completion in an IDE. If you type `myArray.sort<ctrl+space>`, you get all one needs, including `sort`, `sorted`, `sortBy` (which you needed).
Alternatively you could search the reference page for Array or MutableList or MutableMap, not sure what you wanted: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-array/ https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collecti... https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collecti...
var heights: Array< Pair<Int, Int> > = ... //populating the array
heights.sortBy { it.second };
It was not obvious at all that I had to use curly braces. The documentation says: inline fun <T, R : Comparable<R>> MutableList<T>.sortBy(
crossinline selector: (T) -> R?) (source)
This is after I figured out that I'm not supposed to use sortWith (I never figured out how to use this one)The docs are arranged in a way that one reads them in the order they are written (at least the first half). I supposed that would take more than half an hour given at the competition.
I don't think Kotlin is the best choice for programming challenges like codeforces - they really don't let him shine (although I use it whenever I can). But if this is a valid case, we can collaborate and write a short tutorial for C/C++ to Kotlin programmers.
inline fun <T, R : Comparable<R>> Array<out T>.sortBy(
crossinline selector: (T) -> R?) (source)https://discuss.kotlinlang.org/t/examples-in-the-api-docs/16...
I don't want to compare it to Scala, they target different auditories, IMO. I tried Scala, it's a lovely language, but it's too complex. I had to spend a month before I was able to write a quality code using Scala and I still had a lot of problems reading scala collections source code or even understand scalaz. On the other side I spent one evening reading about Kotlin (awesome and very complete, yet small documentation definitely helps) and I knew the language, could read its standard library and write production-quality code. For me that's a deal breaker.
That being said scala is not for one who wants to plateau quickly. It takes years.
With dart news in the past 4 years, the knee-jerk reaction has been that Google will abandon it, which unfortunately means that not much discussion ever went to its merits. Adopting the language has provided a huge productivity boost for me and many other developers, in or outside Google.
Seriously underwhelming....
The 1.1 release is promising many features that make me want to revisit it, though: https://blog.jetbrains.com/kotlin/2016/04/kotlin-post-1-0-ro...
And Gradle is so much easier than the monster that is SBT.
Totally is, but I've had better luck using Maven than Gradle. Having multiple mutually compatible options is great.
Maybe prior to Java 8 this would've been more interesting. I also wonder how much time it will take Kotlin to start benefiting from Java 9 features when that gets released.
There is a slice of the universe where this exists, but it's not really Kotlin's target in the first place (and I think that's basically self-evident from everything around it) so I'm not sure why you'd try to jam that square peg in the round hole to begin with.
Is Kotlin not capable of being a client application?
Runescape also used to be a pretty big one, even if it's been shrinking lately AFAIK.
Many games on Android are also Java based obviously.
(Why are you running things on uncontrolled machines? Don't you have puppet or the like set up so that every machine has whatever it needs to run whatever you put there?)
ABCL - Armed Bear Common Lisp is another, but Lisp on the JVM instead of Haskell. It's been around for a while, and has become fast for a Lisp on the JVM, though it's not SBCL in speed. It does however support full 32 bit integers on 32 bits sytems compared with SBCL's 29 bits on 32 bit systems due to boxing. Again, not used much in production, although, there are some great testimonials of some cool implementations [2]. I particularly like the Keck telescope code written in Lisp in 1994, ported to ABCL and using Java for some image work and display.
[1] https://github.com/frege/frege
[2] https://common-lisp.net/project/armedbear/testimonials.shtml
The declaration-site variance for generics is a pretty good idea, but is still inadequate to deal with functional collections. (I use the term "functional" as opposed to simply "immutable": an immutable collection has no update operations at all, while a functional collection has functional update operations: for example, given a set S and an element X, to compute a new set whose elements are those of S together with X (S ∪ {X}). This usage is certainly not universal, but the distinction needs to be drawn somehow.)
Anyway, the point is this. Kotlin has in its collections API
interface Set<out E> ...
where the use of 'out' says that given types A and B where B is a subtype of A, 'Set<B>' is a subtype of 'Set<A>'. But then if you wanted to add a 'with' operation as described above: interface FunctionalSet<out E> : Set<E> {
fun with(E elt)
}
you can't do it, because type parameters marked with 'out' can't be used for method parameters. fun with<F super E>(F elt) fun with<F super E>(elt: F): FunctionalSet<F>
That's an interesting suggestion, but I don't see any indication that Kotlin provides for type lower bounds in generic function constraints. (It does have type upper bounds; see the bottom of this page: http://kotlinlang.org/docs/reference/generics.html).I fear that it will be hard to move in that direction as long as Google does not push in that direction though.
The official word is that we don't need their support in order to write Android apps in Kotlin, which is true and that the gap between objC and Swift was large enough to justify the change but that Java is not that old, which is debatable.
In all cases, it is hard to argument the move to a new language in an existing codebase when there is no official push in that direction.
If I have to create a new app in the near future, I will strongly consider Kotlin, but for the 8 eight old codebase I have to deal with + the 15 engineers working on it, my hands are tied.
I don't understand the logic behind this sentence? Why do you need Google to push you somewhere instead of you youself choosing a more productive option?
Kotlin is designed to be easy to integrate into existing Java codebase and our introduction to a largeish Android codebase has been a great success.
However, right now I am a senior engineer working on a 8 years old android app alongside 15 other Android devs.
The switch to another language is not even something that the current lead or the CTO are willing to consider.
In their defense, we would have to train the whole team, this would be a major task and build times are already a big issue so anything degrading them is hard to push for.
A push from Google would help a lot, it would remove a lot of objections like "this is hipster shit" or "I am not going to learn the language of the month" (coming from people who have not learned any language in years) and force them to take it seriously.
Even the iOS team barely use Swift though, so I don't see it in a near future. I guess I just have to search for another company.
> our introduction to a largeish Android codebase has been a great success. Do you mind sharing some details ?
Kotlin follows a very similar path as it does, but to greater success. I played with xtend a few years ago and now I use kotlin for my jvm tasks.
Yes. At one job my predecessor had done significant work in Java and somehow the only the compiled files were left behind. We reverse compiled them and that was my starting point for the project. As you can imaging the generated code was perfectly formated, with a very consistent style, and generic variable names. It wasn't terrible to work with.
The language I'm proposing probably couldn't be too different than Java. But one trivial example would be to make all variables final by default unless they were marked "notfinal". This would be different than Java, and thus would be a new language. And it would be trivial to translate back and forth between this language and Java. Nobody could ever tell the difference. Granted all you would really be changing is syntax, which may or may not be worth while.
I would love to learn more about languages and marketing. Off to Google!
Could you describe in detail the problems you had? What was unclear or misleading? Were those problems with the JVM setup or Kotlin itself?
The costs of adopting a new language are greatly more significant than implied here. The time it takes to learn it. The time it turns to learn the tools that are specific to it. And if you put it into production, the technical debt you've created by adding another language to the codebase, etc.
If the OP had said that you don't have to start a green-field project to use it, that would be more accurate.
One reason the cost is low, is that there aren't really many tools specific to Kotlin (or any, really). You can use the same IDEs, the same build toolchains, the same libraries, even the same standard library as regular Java.
I believe Kotlin actually adds programming paradigm that's not in Java on top of terse syntax, i.e. real closure, operator overloading, pure object orientation, and more.
(Don't get me wrong, there are plenty of things Scala would do differently if it were made today - there's space for a language like Ceylon that makes a genuine effort to simplify on what's in Scala)
> Anti-intellectualism is hostility towards and mistrust of intellect, intellectuals, and intellectual pursuits, usually expressed as the derision of education, philosophy, literature, art, and science, as impractical and contemptible. ... In public discourse, anti-intellectuals are usually perceived and publicly present themselves as champions of the common folk—populists against political elitism and academic elitism—proposing that the educated are a social class detached from the everyday concerns of the majority, and that they dominate political discourse and higher education.
The above sentence fails that test, it merely states its roots and goals can be different from academic pursuits. And it is mostly correct: at best academic work is focused on tomorrow, not today..and at worst it is focused on today but should be focused on tomorrow.
Each time someone brings up Scala there comes this weird "people who don't like it are anti-intellectual" - well no, people don't like it because it looks weird, had for the longest time abyssimal IDE support, tries to do things which have been solved in production by itself (see SBT vs Maven) and is a mishmash of more or less every idea that was floating around mixed into one language.
Kotlin has a very specific focus: Being usable for a working Java programmer, who doesn't have three years to learn every weird idea Scala tries to shove down your throat. It uses existing tools, existing Java collections and enhances them instead of saying "well, we do everything new, because we know how to do it 'better' and we don't care for your existing code."
You don't need Scalaz to write Scala code. You can even ignore most of the standard library while you're starting out, and use the Java equivalents.
SBT might seem pointless at first, but the same thing applies there. You don't need to use it, plugins for Maven and Gradle are available. But once you do switch, you'll see how much nicer it is.
The whole "Kotlin comes from industry, not academia. It solves problems faced by working programmers today." is pretty clearly anti-intellectual. I come from industry, not academia, and the Scala type system solves problems I face as a working programmer every day that I couldn't solve in Kotlin (or any other language without higher-kinded types), thank you very much.
> people don't like it because it looks weird
Weird how? I find it looks very much like Python or Ruby.
> had for the longest time abyssimal IDE support
Shrug. Not my experience.
> tries to do things which have been solved in production by itself (see SBT vs Maven)
Just ignore that nonsense and use maven.
> and is a mishmash of more or less every idea that was floating around mixed into one language.
Hardly. It's got a small number of powerful features that get out of your way and let libraries get on with it. Kotlin is far more of a mishmash because it has a whole bunch of special-case functions in the language (e.g. special operators for dealing with nulls, rather than just being a language that people can write an optional type in).
> Kotlin has a very specific focus: Being usable for a working Java programmer, who doesn't have three years to learn every weird idea Scala tries to shove down your throat. It uses existing tools, existing Java collections and enhances them instead of saying "well, we do everything new, because we know how to do it 'better' and we don't care for your existing code."
Scala doesn't shove anything down your throat. You can use the Java collections in Scala if you want - I did when getting started - it's just that it's really valuable to have immutable collection types (actually even in pure Java this is true - one of the reasons Guava is used in almost every project is to be able to have ImmutableList etc. types - but it's better if you can do it without having half the class be "throw new MethodNotSupported()").
I fear it might be very hard to make the Android community adopt it massively though, unless Google pitches in and supports it officially.
And this was done without any official support for Google because... it's not necessary: Kotlin works out of the box. Which is one of Kotlin's strengths.
Do you have any adoption numbers though ? From what I see in the local companies, kotlin is still very rare, except for a couple of startups (which makes them very attractive tbh). That anecdotal evidence of course and I would love to see a tide change but hard numbers would be an huge help.
I'm sorry but you just undercut your own anti-intellectualism better than I could right there.
(There exist languages which have guarded against this without loss of expressive power since before Java and, oh, are from academia.)
Please correct me if I'm wrong, but Kotlin doesn't improve on Java in these areas.
Despite its young age it creates really fast, tight code (they have issues benchmarking things because Dotty Linker + LLVM gets rid of too much stuff).
the point would have been better made by pointing out the excellent and extensive tooling built by jetbrains for kotlin. that's something the maker of the intellij platform has more experience with than academics
Also there is a tradeoff between advanced language features and good tooling, which is why you will sometimes miss the former inside kotlin
So? Their academic status might solve this, but create other problems still.
E.g. lack of an actual commercial ecosystem, too much emphasis on research-y features, immature tooling, etc.
Note the very important part of that statement: It solves problems faced by working programmers today.
Academic PL research can have that property. Pizza went on to be the foundation of Java generics, there's a ton of excellent compiler and GC theory that comes from academic research and so on. And of course a few of the ideas in Haskell and others are leaking into the mainstream.
But when it comes to handling null pointer errors, sorry, it's insufficient to say "some languages popular in academia don't have null". So what? Working programmers today hardly use such languages. They very much rely on languages which do have nulls, and APIs which use them, and yet the only language that came out of academia in recent times which has serious production usage is Scala, which has ... nothing to say on the topic. Except, oh, an option type. Which can also be null, and which even C programmers can easily have. It's simply not comparable to language integrated support with backwards compatibility.
It would have been nice if academic research had identified up front the best set of usability tradeoffs for adding optionality into a backwards compatible language, but nobody did, so JetBrains had to do it themselves.
A few? Don't you feel like you're underselling the impact Haskell had had on other languages?
> he only language that came out of academia in recent times which has serious production usage is Scala,
What are your qualifications for serious production usage? Would ocaml count by your standards? Haskell also has increasing production usage, though I'm sure you don't count it. Swift (if you don't count it now, you will)? Rust?
> It would have been nice if academic research had identified up front the best set of usability tradeoffs for adding optionality into a backwards compatible language,
That's not enough. It would have to be more convenient to use optionals than null or programmers in that language would have to be convinced optionals are better.
In an existing language that uses null pervasively, it would be hard to get a critical mass of legacy code which uses optional.
What are the key ideas that make Haskell unique? I'd say they are pure functional by default, lazyness by default, an extremely terse syntax that relies heavily on symbols, effects in the type system, type classes, and a few other smaller things. As a non-Haskell expert at least, these are the ideas I associate with the language.
Writing code in a more functional style is steadily becoming more popular, but functional by default does not seem to be the choice of any modern language targeted at the mainstream. Swift, Rust, Kotlin, Ceylon, Go are all examples of industrial languages developed outside of academia that do not follow this design choice, and their functional programming support primarily consists of map/filter/fold/etc type methods on collections and sometimes (as with Kotlin/Java) a lazy sequences library. Meanwhilst, whilst often convenient and intuitively helpful, the evidence that fully pure functional code is of much higher quality than mixed or mostly imperative code is ... lacking. Certainly it's difficult to get clear evidence without controlling for other factors like experience of the programmers.
Lazyness by default is an equally un-influential choice. It seems Idris is the newest cutting edge academic pure FP language and it's strict by default. Lazyness by default creates an entirely new class of bugs that developers didn't have to think about before, for little obvious benefit (it lets you write in a certain style more easily, but does that style really give better software? again, it's difficult to get robust data on this).
The extremely terse syntax that relies heavily on symbolic operators is widely regarded as a bad choice. Modern industrial languages like the ones I named have all shunned this type of design and Kotlin, for instance, doesn't let you define arbitrary new operators. Haskell code is often rendered much harder to read than necessary due to its abuse of symbolic operators.
Effects in the type system do feel nice, but the impact of this idea has likewise been limited. You could argue that Rust's borrow checker is perhaps somehow inspired by this, although it's sufficiently different that I'd describe it as original work rather than idea that comes from Haskell. Other languages haven't focused on it so much.
I suspect the next idea to cross over from Haskell will be type classes, or a variant of them. But probably as an obscure feature not many people use, rather than a fundamental building block as in Haskell.
All in all, given the level of attention Haskell has received for many years, I feel its ideas have had surprisingly little impact.
With respect to "serious production usage", that was obviously a lax description. As far as I know there's much more usage of Scala in the non-academic world than O'Caml or Haskell, but it's still quite a small amount relative to languages like Python or Java. I don't have any specific thresholds, it was an intuitive description.
> In an existing language that uses null pervasively, it would be hard to get a critical mass of legacy code which uses optional.
Exactly, but that's what Kotlin is trying to do through its auto-convert from Java to Kotlin, the backwards compatible type system, support for nullity annotations and so on. It's got the closest yet.
So it will end as iOS only.