Having used Kotlin on and off for the better part of a decade, the one thing I can say is that their editor support is unrivaled by any other language today. While Kotlin's build tools leave much to be desired (looking at you, Gradle), their focus on building a "toolable" language was the right thing to lean into. You can add all the fancy type system features you want, but if the IDE does not understand them, convincing users is going to be a hard sell.
Whenever I try to get into another language today, the lack of language-aware editing tools are my main source of frustration - specifically, I expect navigation, refactoring and completion to work flawlessly. I know of no other programming language that puts as much effort into context- and structure-aware refactoring - if another language does one day replace Kotlin, it will need to offer a comparable editing experience.
I attribute this to the fact that Kotlin was developed by the same team that created IntelliJ, and fantastic IDE support was a requirement from day zero.
A big part of why Kotlin works is because IDE support is so fantastic now. And likewise, a lot of the reasons Java ties developers' hands is because there was no guarantee about the IDE they would be using.
As a trivial example, declaring variables. In Java, you have `final String foo = "bar";` while in Kotlin you can just say `val foo = "bar"`. They type is implied, but if you aren't sure, you can hover over `foo` and the IDE will tell you what the type is, so there's no longer a reason to type it out every time.
Also, you can now have multiple classes in a single file. When Java was created, the one-class-per-file rule made finding the source code to a file easy; just do a `find` for `Classname.java`. But with a modern IDE, you can just command-click an instance and be taken to the source code automatically.
Java's boilerplate is meant to make code discoverable, but the Kotlin IDE does that work for you, allowing developers to be more flexible.
This is funny because the other language I think of which wouldn’t be nearly as popular without an IDE, is Java. Especially older versions of Java.
Java is way too verbose to be workable if I have to write out all of the class declarations and anonymous classes and “equals/hashCode/toString” boilerplate and “ExtremelyLongClassName foo = bar.extremelyLongMethodName(…)”; and there are too many pitfalls like comparing with “==“ instead of “Object.equals” and implicit null. Except that I don’t have to write out anything or worry about any pitfalls (well, implicit null still hits me sometimes, but @NotNull and @Nullable make it much less common) in IntelliJ. IntelliJ has such powerful and seamless analysis, it does aggressive code folding on Java 7 so that you are looking at code with “var”s and lambdas. It also has built-in support for popular libraries like Spring and Lombok.
IntelliJ single-handedly turns Java from a verbose, legacy language into something I could actually recommend and start new projects on (although at that point I usually go with Kotlin). And Eclipse, NetBeans have very deep Java analysis as well. Java may have started off without expecting IDE support but now IDE support is responsible for a large part of its popularity.
Yes. You either have a language that is easy or you have tooling to make it easy.
If I cannot access documentation for a library/function at a mere tap of a button - that language isn't going into my toolbelt. I have to code in like 5 languages at my dayjob, that's at least 3 different types of semantics for ==.
Java, and Kotlin, are great at that. It's the major pitfall for Scala(and a laundry list of others), on the other side(hey implicits and converters, that make even IntelliJ go "wut?"). Those long names in Java are actually a godsend. Give me "int indexInTheArray" over "int x" anyday. Explicitness of Python is also a pleasant thing to work with.
People forget that most software is boring website backends, business processes and similar tools. Most devs don't have mental capacity to devote to "the one and only" language+platform+ISA.
It's not just the tooling. Having tried to work with Python in Intellij, the lack of typing means you literally have to GUESS what any non-primitive object can do.
It might also be an unhappy coincidence, but the library I was playing around with (scrapy) also had HORRENDOUSLY documented code. With Java/Kotlin, you can just click into any method/class and you'll get a useful doc string 99% of the time. With Python, I had to read the (incomplete) documentation.
This sort of flies in the face of how many people reject lisp systems, though. I could almost see that python is doing this, but the number of python users I have met that don't know how to use "help()" is... impressive.
I'm curious how you come to this conclusion. Granted I never wrote much Java (and not in the last 10 years), but it was painfully verbose at the time. I've never had that reaction while writing golang (which over the last 3 years I've done a decent amount). Has Java gotten much more succinct?
That’s the interesting thing, how did this verbose feeling stuck to Java while not to Go, where your code is literally littered with if errs, you have way too deeply nested for loops, etc.
Java is a surprisingly expressive language even though it does have a few warts.
I'll have to give it another look if the situation presents itself. I think one factor of Java being remembered so unfavorably was it being early in my career.
I do think there should be a distinction on what is lumped as verbosity. Golang is vertically verbose with its error checking, and Java in my experience is at least more horizontally verbose (long lines).
> As a trivial example, declaring variables. In Java, you have final String foo = "bar"; while in Kotlin you can just say val foo = "bar". They type is implied, but if you aren't sure, you can hover over foo and the IDE will tell you what the type is, so there's no longer a reason to type it out every time.
This is something I've learned about Groovy that I really like. You can declare variables in multiple ways (terms are my own):
foo = 1 # normal assignment
var foo = 1 # declared assignment
int foo = 1 # typed assignment
A lot of our current code used the first "normal assignment" that you would see in shell scripts, Python, whatever. There's nothing interesting about this.
I started using the second kind consistently. The "declared assignment" says "I am creating a new variable foo and its value is 1". If you are not creating a new variable (i.e. if the variable exists already) your program fails. This is a great way to ensure you're not overriding variables from earlier in the program or from another scope. My experience tends to be that this throws errors "now" for mistakes you're currently making (at this point in the control flow) by overwriting a variable that existed before.
The last is a "typed assignment", where you're not just saying "I am creating a new variable", but specifically the type of variable is important. This errors if you ever try to misuse a variable down the road, and helps with ambiguity. It solves the "somestring = somestring.split()" issue of discounting a variable as the potential issue due to "it can't be this one, that's a string" being right for a while and then wrong for a while (or vice-versa).
Anyway, all that to say: not having to specify data types is nice in some circumstances, but I've been leaning into adding data types to my code just to make absolutely sure I know what everything is all the time. Not having to in Kotlin sounds nice, but I hope there's a way to be explicit about everything.
I think many of us have stale conceptions of Java formed decades ago. But some time ago, Java started evolving quickly and now isn’t that far off from Kotlin. When Kotlin started, that was not the case.
People still think of Java as stuffed full of wordiness, slow startup, garbage collection seizing up code, and long compile times, but that’s all in the past.
I'm not so sure about the slow startup claim here :-) I.e. Spring apps still take several MINUTES to start (with Java or Kotlin...)
Please correct me if I'm wrong, but I don't think Java's dependency discovery mechanism has evolved much (if at all) from prehistoric times (hence, the slow startup remains). Although GraalVM sort of addresses that.
I think you are right. Many also got their first experience with Java in school or at their first job. Languages like Java/C# can seem intimidating at first.
As a long time Visual Studio and C# .Net developer it’s always fun to hear people wax lyrical about these “amazing new” IDE features that have been pretty much standard in the toolchain for more than a decade…
So long as everyone on your team uses IntelliJ, then no problems. But not everyone uses IntelliJ, and now you've written code that is only easy to parse in a particular IDE...
For this reason, and being able to read my own code outside of just my IDE (say, in Github, etc), I've found it more necessary to be explicit with my typing in Kotlin for all but the most trivial snippets.
This is not a compelling argument. I'm not going to stop using a powersaw to cut beams just because another contractor refuses to use anything but his handsaw.
Besides, reading implicit types has _never_ been an issue on any team or collaboration effort in the 30 years of my programming experience and I find it _really_ hard to believe anyone that claims it is a bonified problem for readability. In fact the complete opposite is true for me, personally, that too much information in front of me becomes noise and the signal gets lost.
They're not talking about someone using a hand-saw, they're talking about someone using a powersaw from a different manufacturer. Or, y'know, a table saw, or a CNC machine. Kotlin has tight integration with one particular IDE, not with all IDEs; let alone with things that are powerful in ways orthogonal to the ways IDEs are powerful, e.g. Emacs.
Considering that many people willingly work with languages like Python and JavaScript, which make ANY IDE/Editors job of completion horribly difficult, the worst case is you end up with an editing experience on par with other languages.
I would argue that C# and Visual Studio (and maybe Rider) has as good, if not better tooling integration compared to Kotlin, especially considering nuget and sln files solve the “build system leaves things to be desired” part of your comment.
This isn’t to say that Kotlin isn’t absolutely incredible, but I do not want to undersell the pleasure that C# is to work in with its tooling.
what do you have in mind about refactoring support with Typescript and VSCode? Maybe I'm missing something obvious but the only "refactoring" functionalities that VSCode provides me are "rename this variable", "rename this file" and "move this export to a new file" (can't move to an existing file, and can't even chose the name of the new file)
In VSCode what's in the refactoring menu depends a lot on what you have selected or under the cursor. For example with a selection of a block of code you should get the "extract to method" menu item appear in the refactoring menu, etc. I don't remember there being quite as many as what IntelliJ has for Java though.
I've used both and Kotlin was a better overall experience for me. TypeScript has weird typing problems far more often due to the underlying runtime being dynamically typed.
While I like TS and it is my primary language currently, having worked with Kotlin in past I find the dev experience with kotlin to much better, esp. if you steer clear of libraries that lean heavily on bytecode weaving, compiler hooks etc.
Kotlin's type system is nominative and so while it is not as flexible as typescript (no intersection types, conditional types etc.) it also means that you don't run into those multi-page long type errors which need 5 mins of debugging to figure that some deeply nested object is null where undefined is expected.
It is particularly funny when the language server truncates the errors and it becomes impossible to infer the actual issue from the message. Every now and then I find myself extracting things out of objects and adding type annotations to simplify the errors. It is doable, but never needed in Kotlin.
Types in TS are Turing Complete [1], so any static analysis you build ontop of that language is bound to be unsound or undecidable. You could argue this rarely occurs in practice, but I would prefer a type system that is incomplete but sound and decidable. Incidentally, this issue also affects Java, which is both unsound [2] and undecidable [3]. Kotlin does have a fairly complicated subtyping relation [4], which has caused similar issues in languages like Scala [5], however whether the same issue affects languages based on mixed use-site and declaration-site variance like Kotlin is still an open question and requires further investigation.
TypeScript works well because they don’t worry about soundness and completeness. The type system isn’t trying to be perfect, just useful. This scares PL theorists, but I think it has been a very profitable corner of the design space to explore.
Variance rarely comes up in Kotlin because they don’t push immutability as much as Scala did. It’s like, there as an option but I’ve used it a total of two times in the last two years of full time Kotlin programming. Compared to typescript, Kotlin is fairly boring, but it is tooled well and is a vast improvement over Java.
Jetbrains and rust have brilliant refactoring. No idea how it compares to kotlin, but I can confidently move methods to other modules and files, rename anything, navigate to definition with no fear. Auto complete / auto import is also insanely good and is almost to the point where I’m auto completing almost every symbol because the IDE knows what I want precisely.
That's a JetBrains thing - they added loads of fantastic refactoring options to Visual Studio for C# which have now largely been integrated into the IDE directly. I've had an all-products subscription for close to a decade now and it's money well spent.
ReShaper was what kept JetBrains alive 10+ years ago and Microsoft couldn't release a new version of Visual Studio until ReSharper was ready for it due to how many people used/depended on it.
Kotlin has one of the poorer LSP implementations out of the popular JVM languages. Last I tried it was buggy, and slow. Developers are pushed into using JetBrains products directly or indirectly (Android Studios) I suspect leaving the wider ecosystem poorly supported.
I was evaluating Kotlin for a Spring Boot project a few years ago and would have loved to have programmed in it, but this was exactly why I stuck with Java.
Back when I was doing audits, the only languages that really had good IDE support for that were objective-C / swift using XCode. You could get a caller hierarchy and get some sort of recursive dropdown menu to go through the entire call stack, it was magical.
Last I was looking into Kotlin (couple years ago) they seemed hostile towards efforts to bring a similar level of support to editors outside the Idea family; basically they weren't going to do or support anything that threatened their "walled" garden of Kotlin + Idea. Is that still the case?
As a huge fan of Jetbrains products (I maintain a personal IDEA Ultimate subscription) this was still a huge turn off to me.
> I know of no other programming language that puts as much effort into context- and structure-aware refactoring
Do you mean JVM language? TypeScript, C#, and F# at least come to mind.
> Do you mean JVM language? TypeScript, C#, and F# at least come to mind.
As I mentioned in another comment [1] on this thread, soundness and decidability are non-negotiable for me. Types in C#, F# and TS are all Turing Complete [2], and therefor these languages are tooling-adverse in the sense that static analysis is fundamentally unreliable.
> As I mentioned in another comment [1] on this thread, soundness and decidability are non-negotiable for me. Types in C#, F# and TS are all Turing Complete [2], and therefor these languages are tooling-adverse in the sense that static analysis is fundamentally unreliable.
How on earth do you consider Kotlin acceptable then? Kotlin's type system has never been shown to be sound or decidable and is visibly a lot more ad-hoc than any of that list (and if by some miracle it was sound or decidable last week, I'm sure whatever new feature they added this week broke it). I suspect the only reason it hasn't been formally proven to be Turing Complete is that Kotlin's developers haven't bothered to write a specification for it - as far as I can see your link's example for C# would translate directly into Kotlin with the same properties.
> Try it! I certainly have. You may find encoding a typelevel TM or λ-calculus more difficult than it appears...
These languages were stable, well-specified, and heavily studied for years before these cases were found. One person noodling around for a few weeks failing to find an example is not evidence of anything; a language being too obscure to have seen much academic study is not an indicator that it's likely to have a good type system, if anything it's the opposite.
> T isn't generic in that code, it's just a class.
I think it needs to be a generic type in Kotlin for this to work, because otherwise it will dispatch to a single method. It's tricky to get Kotlin to do much compile time computation. Not saying that it's impossible, but LMK when you've actually tried it. Here's some sample code if you want to try encoding a Boolean logic:
> Well, I've been trying for about three years, but to be fair I'm a pretty slow programmer so you may have better luck.
Well, your own link proves it, doesn't it? Kotlin has nominal subtyping, contravariance, and generics, therefore its type system is undecidable.
> I think it needs to be a generic type in Kotlin for this to work, because otherwise it will dispatch to a single method.
That's the whole point - the type system has to decide which overload to dispatch it to at compile time, which it can only do by performing an arbitrarily complex computation. I ported that code directly to Kotlin and it doesn't compile but it "should", which, well, I don't know what you were expecting or what you'd accept as proof when we've already got an academic paper that proves the point.
That code simulates a bounded cellular automaton, which effectively reduces to a regular language, but that's about as far as I've been able to get. If it's possible to implement general recursion, I'm not quite sure how - yet.
> Kotlin has nominal subtyping, contravariance, and generics, therefore its type system is undecidable.
They're not using Kennedy and Pierce's system, but it's closely related. See Tate (2013) [1], in particular, "In general, since declaration-site variance can easily be encoded into use-site variance..."
> I ported that code directly to Kotlin
Can you share your translation of Eric's code? Maybe we can get it to work.
> They're not using Kennedy and Pierce's system, but it's closely related. See Tate (2013) [1], in particular, "In general, since declaration-site variance can easily be encoded into use-site variance..."
Well, Kotlin has both declaration-site and use-site variance. So surely that result applies.
> Can you share your translation of Eric's code? Maybe we can get it to work.
Literally majority of languages are either unsound, undecidable or both in the link that you've provided. The only exceptions are Haskell, Idris, ML and Go (given the date of the post, this was pre generics which would probably exclude it also).
That's certainly a design choice they're free to make. Undecidability itself is less of a deal-breaker, although I would argue that a statically-typed language which is unsound defeats the purpose of having static types in the first place.
Ideally, you want type inference to terminate in the amount of time it takes to type a few keystrokes to get realtime assistance, so decidability is still an over-approximation from a tooling standpoint and in practice anything strongly super-linear is not a fun experience to use.
The premise was "toolability" in language design, which is one of Kotlin's main design principles. To do type-safe completion, navigation or refactoring, you need soundness, and to do it rapidly in the context of a live programming environment, you need to be able to resolve a type with keystroke latency. Rapzid asked [paraphrasing] "why not TypeScript, C#, or F#?" to which I responded that I do not consider these languages "toolable" because type checking is essentially broken (i.e., it might take forever, or give the wrong answer).
> Was there some study done...?
No, not that I am aware of. If you find one, I would be keen to read about it.
I don't understand how you can come to the conclusion that type checking is broken and the language is not toolable? Can you give an example of where Kotlin's tooling achieves something that is not achievable at the moment in a C# IDE?
(I've not used Kotlin much but I have never felt that the tooling for C# was lacking, so I am genuinely curious)
Yes, and to be clear I have never encountered these issues on practical problems. I am also not claiming Kotlin has or lacks these properties, just pointing out the fact if you care about toolability, soundness and decidability are important factors to consider and if there is a language design issue, it makes me less confident in any tooling which is built around it.
It comes down to whether you want type checking to work all the time, or most of the time? If your answer is "most of the time", then just use a dynamically typed language with GPT-based autocompletion. Most of the time completion and refactoring will work just fine.
Re: type checking in C#, maybe try the following example?
a) "most of the time" being 60% (very roughly what I'd expect when doing renaming beyond a single function in JS, and that's being optimistic).
b) "most of the time" being 99% (very roughly what I'd expect in a typical C#/java/kotlin codebase that isn't using too much reflection).
Even aside from that, I'd argue that nullability, array covariance, and reflection all have MUCH bigger practical impacts on typechecking reliability than Turing-completeness. Most languages will simply fail to compile if the computed types require too much recursion, making the issue relatively moot.
Type-checkers don't actually need to solve the halting problem to be sound, they just need to guarantee completion for _most_ types of code, and anything that can't be guaranteed can simply be rejected.
I would expect this number to get closer to 99% with LLM-based AI code completion tools, so the gap between dynamically-typed languages and "good enough" languages that claim to be statically typed (but are in fact unsound) will become much less significant. But if you want correctness, you will need stronger guarantees.
> I'd argue that nullability, array covariance, and reflection...
I would mostly agree with that statement, with the caveat that it depends on what you want from your type system. Personally, I want the checker to be (1) sound and (2) decidable and (3) fast. For everything else there's runtime type checking.
> Type-checkers don't actually need to solve the halting problem to be sound, they just need to guarantee completion for _most_ types of code
Although I don't see much difference between undecidable type systems and dynamically typed languages, as I wrote, I see undecidability as less of an issue. My main concern is unsoundness, which is more critical and unclear how to fix. By "soundness" I specifically mean the formal property that "well-typed programs cannot go wrong". "Most types of code" is just a statistical claim, in which case you might as well use Python or JS/TS with a linter. Too many statically-typed languages decide to go off and roll their own types without reading PL literature, then end up with dealing with these issues later down the line.
> It comes down to whether you want type checking to work all the time, or most of the time? If your answer is "most of the time", then just use a dynamically typed language with GPT-based autocompletion. Most of the time completion and refactoring will work just fine.
This is bad advice. Such an approach will go wrong often enough to burn you, and it will go wrong silently, whereas the kind of issues you describe tend to lead to something far more visible (and therefore correctible) like a complier internal error or an IDE refusing to perform a refactor.
Have you used TypeScript? Not only is it better type system than Kotlin, it has great IDE support in VSCode, AND there’s a language server so you can get IDE support in Emacs/vim.
I'll bring up the Kotlin LSP[0] every time I see Kotlin on HN because I really hope the LSP takes off (which would make it viable to use Kotlin with a non-IntelliJ editor).
Kotlin as a language looks really cool, but I don't want to give up terminal-based, modal editing (which I'd have to in order to use IntelliJ).
Along those lines, I once tried diving into using Gradle outside IntelliJ, and I couldn't find any good resources to help with that. If folks have hints/links-to-blog-posts with regards to that as well, that'd be great!
Totally the opposite - I think that's really from Scala's first versions of so.
But Scala has a steep learning curve for the advanced techniques and the compile times can be very annoying when using those. And if you don't use the advanced techniques, you might as well pick Kotlin or Java instead.
Is that list of disadvantages really accurate? Reading them, I get the impression that the "popularity gap" between Kotlin and Java was a major reason FB was behind the industry on converting to Kotlin. (For context for non-Android engineers reading this, Kotlin has been the first party recommended language for 3 years now, and has been supported for 5 years) I can't imagine y'all were interviewing Android candidates in Java? And while certainly the Kotlin ecosystem as a whole is smaller than the Java ecosystem, the Java Android ecosystem is miniscule.
My recollection from my time in the building at IG was that build times and binary sizes were the two heaviest lifts, almost to the exclusion of anything else. Am I misremembering, or did the conversation change? Or does that list of tradeoffs reflect a realization by your team that you'd need to convert everything to Kotlin, not just the Android code?
I think this is a good depiction of our worries. Our biggest is and always was build times.
> I can't imagine y'all were interviewing Android candidates in Java?
We let people choose their preferred language for a while now. Also, while this blog is celebrating some milestones in the conversion, some smaller apps and new code was using Kotlin for a while now.
> My recollection from my time in the building at IG was that build times and binary sizes were the two heaviest lifts, almost to the exclusion of anything else. Am I misremembering, or did the conversation change? Or does that list of tradeoffs reflect a realization by your team that you'd need to convert everything to Kotlin, not just the Android code?
Binary size has generally not been an issue. Build times are an issue. We migrated and migrating some optimizations we have to alleviate that. We're also crossing fingers for more wins from the new Kotlin compiler JetBrains is working on.
1 & 2) Yes, almost all of the mobile code lives in one repo, and the 10M number quoted is all in one mercurial repo.
3) There's a lot of different things we do to work around such issues. Some things that come to mind right now:
- We have plugins for Android Studio to avoid loading all the code at once that help.
- We had forks for the Kotlin plugin for Android Studio to deal with some issues that were worse for our repo. (especially around module loading)
- We also worked with JetBrains by pushing some fixes and they fixed a lot of the issues over time.
- We do a lot of work as async jobs that run on the repo without you waiting for them, so you don't have to wait for such tools.
Have you released the source code for the following (primarily running AS in headless mode). It's something I've wanted to look into adding into our CI:
> As part of this step, we also apply our autocorrecting linters and apply various Android Studio suggestions in headless mode.
I'm not the right person to comment on the React Native part. (There's definitely quite a bunch of React Native in the app on top of the Kotlin)
Other people are also working on Obj-J/Swift, but from my superficial knowledge I think it's a much harder migration to do. I really think the Kotlin team did amazing language and tool design which makes Java to Kotlin migration easier than almost any other language migration I could think off. Kudos to them.
- The Facebook app is huge in terms of features. Just look at the menu with more things. I use very few of them, yet they're all pretty popular and justify themselves.
- Instagram is smaller than Facebook, but still has a lot in it.
- A lot of our code was optimized over time in many ways that add a lot of edge cases: internationalization, accessibility, optimizations for dealing with media, loading and data. It's can be easy to write something with much less code that looks pretty good at first sight, but all those extras really make the experience better and pay off for users.
- We build new features all the time, some code may be unreleased, some is in A/B testing and so you can have two or more pieces of code that do the same.
- A lot of test code.
- Not that much dead code. Trust me. I love deleting code! And I will happily spend time removing bloat. There's definitely a lot of dead code to remove, but it won't change those top line numbers by much.
(Also, it's 10M Kotlin lines of code, we have much more)
(I would love to know how many lines of code the other really big companies with big mobile apps have for comparison)
> Today, our Android apps for Facebook, Messenger, and Instagram each have more than 1 million lines of Kotlin code, and the rate of conversion is increasing. In total, our Android codebase has more than 10 millions lines of Kotlin code.
Probably 1000 engineers working on an app with each writing 1000 lines of code. I am not surprised Facebook app has >1 million lines of code. The app is bloated with features that it's user unfriendly.
I have parents that are pretty not tech literate (they didn't how to save contact or send SMS) but they have no trouble navigating Facebook app for the core set of features they use.
I would like to know your arguments against it. How would you define a maximum count of LOC, why would you set that particular limit, and how would you address the "problem" if your team were to hit that limit?
We're transitioning to Kotlin. And our main problem with it is slow compilation.
With only Java is was <2mins and we're touching 10mins now.
I'm not sure what exactly the problem is as we still have to investigate. Our use of Kotlinx.html (which we absolutely LOVE as HTML templating tech) seems to be a part of the problem, but we have not gone to the bottom of it yet.
Nothing against the language, everyone on the team loves it (when Java is what we consider normal). The extra type safety we get out-of-the-box or have put some effort into (using KFunction all over the place) is really paying off.
I wanted to post that ktfmt, the FB Kotlin formatter, is much less well-known than ktlint.
IMO, it produces the most (subjectively) readable code, and is the only one that doesn't leave room for you to inject personal style in certain places. (ktlint will let you get away with one of several ways of formatting code, so long as it falls within some guidelines, which can lead to inconsistent formatting).
These two formatters both suffer from the flaw that what intellij does when it autoformats is different from what either of those two do and can only be controlled through plugins. Especially when it comes to controlling imports this stuff is just broken in Intellij. The settings for this are not actually part of the code formatting settings.
Most sane code formatters & code standards: "don't use import wild cards!" Intellij's default since forever: "wildcards all over the place; please jump through hoops to get rid of them".
I've given up on having code formatters in my kotlin builds for this reason. Just not worth the hassle of trying to make both sides just do the same thing by default so I don't have to think about it. And then having to explain to every new team member how they have to customize their intellij setup so it isn't broken. I just gave up on it. These days I tell people, auto format your code, leave the settings alone. Try to only format the code you modified to avoid endless formatting related diffs.
The fix would be for Jetbrains to finally fix their IDE to have proper formatting that includes the behavior of organize imports and is perfectly in sync with whatever your build file says is the code style rather than whatever manual or built in stuff. Any IDE settings for this should IMHO just be removed as they are completely and utterly wrong in the presence of a build file that says how things should be formatted. Just default to whatever your build file says is the code standard with some sane default that just comes with the kotlin compiler. This should not be optional. You want to override it: do it in your build file.
Auto format on save in intellij. CI build verifies that nothing is mis-formatted because the IDE did it right because it does whatever the build file specifies needs doing without second guessing that. Have a githook to format before commit (optional). Zero manual fixing of anything ever related to formatting. It should not have a chance to go wrong and break the build unless somebody forgot to format or have a commit hook to do so. Just import the project and everything does the right thing. That would be the goal. IMHO it's not technically hard but it would require addressing what is likely to be quite a bit of technical debt related to this in intellij. And it's about time they did that.
Not sure what's preventing you from setting up Intellij to do what you want, even without .editorconfig. I setup intellij editor format preferences to follow the formatting I setup with my build-based linter/formatter. I just change the IDE settings so that they match my formatter, use it as the project setting, and then commit the codestyle files in .idea folder so that it's always there when I import or open a project. Never have to touch it again, autoformat in the IDE works and is 100% compatible with my ktfmt, ktlint, checkstyle, spotless or whatever. Imports, order, line wraps, indentation, etc... it 'just works' for me.
Yes, it's a minor additional step at first, but it's like 15 minutes tops, and after the first time you do it, you simply copy the xml from project to project if you want to use the same settings.
What you are suggesting here is a lot of manual work. What I'm complaining about is that there is no sane/easy way to avoid having to do all of that and getting everybody on the team to do the exact same things.
This should be as simple as "import the project". Done. There should not be any extra steps. No settings fiddling. No magic files to copy. No plugin installations to intellij. Etc.
You wrote this entire comment but ktlint can generate a .editorconfig (and in fact used to generate a IntelliJ specific config file) which is a universal way of solving this exact problem.
Pretty sure the FB equivalent also has a matching .editorconfig
Also you could just setup a prepush hook so they run before your CI does which afaik both give you examples of.
The only time the pre-push hook fails is if a line is too long and there's no "canonical" way to fix it (so it'll create a method chain for example, but it won't do string concatenation since there's N ways to break a string across lines)
When was that? IS that a big codebase? I fixed a memory leak issue a few months ago that would have a big effect when running over hundreds of files at once.
More than a few months ago, and a fairly large codebase (~1000 files).
I might give it another try for some personal projects since I did like the anti-bikeshedding angle with respect to configuration, but yeah linting can be a hard sell once build performance starts to suffer for it
One thing that Kotlin got going for it is the tooling. I mean, the creator of Kotlin creates some of the best programming tools out there so I'd imagine (without actual experience of Kotlin) that it has great tooling.
Sometimes, the tooling is even more important than language features IMO. It makes developers move quicker, find bugs easier and so on. I like the idea of Kotlin, that it can compile to jvm bytecode, javascript and native.
So in essence, I can use the same language everywhere in the true meaning of the word.
> Sometimes, the tooling is even more important than language features IMO. It makes developers move quicker, find bugs easier and so on. I like the idea of Kotlin, that it can compile to jvm bytecode, javascript and native.
The only thing I'd worry about is Java overtaking it.
Do you remember Coffeescript? There was a point in time where it had impressive adoption, and quite a bit of buzz. But then Javascript added features, and all of a sudden the tooling burden associated with Coffeescript just didn't make sense any more.
With Oracle's 6 month release schedule, that's a distinct possibility. Especially since Java can no longer rest on its laurels as a language (if Oracle doesn't want it to become Cobol 2).
* Android is a massive platform, and Android is basically stuck on JDK8 (or JDK11 with desugaring, wooo).
* iOS compatibility-ish. KMM is not ideal and mostly generates ObjC compatible objects (so generics are mostly screwed for Swift and writing iOS code is not ideal, but even being able to define common and enforced contracts is cool. iOS benefiting from projects like SQLDelight is super cool)
* Jetbrains hedged their bets, and Kotlin/Multiplatform is a solid option. Coupled with Jetbrains Compose for UIs as well as having the entire Java ecosystem available is very solid. Compilation for so many platforms, directly to native executables is cool.
* Java is still very slow to evolve. Kotlin has had data classes for a long time, Java recently added records. Inline classes offer some nice type safety at basically zero costs. Coroutines and structured concurrency are a beautiful way to work, and Project Loom would only build the foundations of that. Context extensions (while terrifying in the potential for spaghetti code they offer) are a useful feature, reified generics have some great potential.
Now, Kotlin has its disadvantages too. Compilation times are not that great (hopefully K2 fixes this partly), but it's relatively safe and is kind of more than just a JVM language by now.)
I agree with everything you said except for "Java is still very slow to evolve."
New Java versions are cut every six months since 2017 and since then has added a significant amount of new features, syntactical sugar, APIs, et cetera. Not only that, but they've also have been pretty aggressive IMO in deprecating and removing legacy. Very very different than the Java I remember working in years ago.
The hesitancy in jumping beyond JRE8 is the large backwards compatibility road bumps in JDK9-11, and now again with 17/JavaEE->Jakarta. I wish Java would continue to add new features but be a lot more considerate of avoiding, completely, migration headaches.
We are migrating Java 8 -> 17 now and it’s been a right royal pain. I’m glad we didn’t jump to 11 LTS, and instead make one big leap. It might be a very long time before we do another LTS upgrade if they keep making poor migration choices.
The only relatively bumby migration was 8->9. After that it is a very smooth ride, and that bumpiness was the price for the accumulated tech debt/slow down from the end of the Sun era.
Well, my understanding is (but I have yet to personally experience) the migration from 17 -> 18+ is rough because of all the javax.* packages being renamed jakarta.*
Which likely means touching a pretty significant portion of your codebase for the upgrade, and then who knows what 3rd party libraries you depend on are expecting...
So it may be as simple as Find/Replace for some folks, for others, it might be a deep dark rabbit hole.
Not breaking things used to be Java's MO. Yes, that means a ton of legacy cruft built up over the years... but we used to be able to depend on Java to "Just Work".
Perhaps some of this is necessary. After all, the C# folks seem to have no problem breaking everything to add new features... but I'd assert the Java community as a whole is much less tolerant of breaking changes and rapid deployment of features.
There are entire segments of the industry that has never touched any javax package - while no doubt widespread, I do believe that it is still a very fair price to pay, and none of these changes were even half as problematic as for example the python 2->3 migration. So I don’t know, I’m fairly sure it is impossible to keep a platform alive with even less/smaller impact breaking changes.
In HN a while back, an Oracle dev pointed out that the evolution is slow for a reason. Which confirmed slow. New releases every 6 months, but not that much in the way of changes.
This isn't criticism of the fact of it or going into why it is or whether it should be that way. It's just a statement of fact.
You're correct of course, but to back up the parents comment, they do have a habit of implementing things other than the low hanging fruit that developers are frustrated not having, leading the drive towards other jvm langs
Functional/SAM interfaces (transforming interfaces with a single method into a simple lambda), pleasant usage of lambdas (last lambda parameter can be put outside of the call like(this) { ... }, leading to a language that lends itself really well to building a DSL, coroutines were not a low hanging fruit but absolutely are infinitely more pleasant to use than RxJava, operator overload including invoke(), ranges that are pleasant to use (0 .. 10).forEach { }, or when (floatVariable) { in 0.0f .. 1.0f -> ... }, pattern-ish matching with when (not quite full on functional language powerful, and I believe that Java is not only catching up to it but making their switch quite a bit better), a standard lib that is packed full of extremely useful and consistently named methods, extension functions, delegation (if you inherited a SDK that has a piss poor interface, you can simply make a SDKWrapper(val internalSdk: SDK): SDK by internalSdk, which means that it will automatically implement it, and you can then have your wrapper do whatever around it (logging, better functions, DI, etc.)))
Kotlin is truly a pleasant language, both when you don't know it (although it can look a bit symbol soup-y at times for juniors), and when you fully know it.
Just browse through the Kotlin standard library. It's basically just a set of mappings to the Java standard library with a whole lot of extension functions to make it easier to use.
I don’t know how well it works, but we have seen these kinds of projects, and they seldom work as is. Not sure how well Scala Native works, even though it predates Kotlin’s try. (Though scala.js is surprisingly good!)
But do you really think that a relatively young language like Kotlin with minuscule adoption (compared to java) will be better at this game then Java?
Java has a very good compiler to Js maintained and used heavily by Google (j2cl, part of their closure compiler toolkit), which can also output obj-c code. These are/were used heavily for porting their shared libs between basically all platforms.
For native, Graal is a very cool way forward benefiting all JVM languages (as well as scripting languages, its polyglot features are insane).
> Java is still very slow to evolve
Is it a problem? The majority of developers don’t like running after the language, even though it may seem so based on online hype circles.
Well enough, provided you stay within the known bounds. Hell, some people at Touchlab even went as far as porting Jetpack Compose to work on iOS (which, uh, I would not recommend in its current state), and it technically works. I probably wouldn't recommend writing all of your app logic in Kotlin, but being able to share the data layer is amazing.
>But do you really think that a relatively young language like Kotlin with minuscule adoption (compared to java) will be better at this game then Java?
It depends on where you're looking. Most modern android development will most likely be done in Kotlin. Backend work, for things started relatively recently, Kotlin is not surprising. But mostly, Java does not make iOS compatibility a goal. Java tell you "get a JVM and run our shit" (or get GraalVM and have basically an embedded JVM). Kotlin has two sides, and Kotlin/Native does not depend on the JVM.
>Java has a very good compiler to Js maintained and used heavily by Google (j2cl, part of their closure compiler toolkit), which can also output obj-c code. These are/were used heavily for porting their shared libs between basically all platforms.
j2cl still brings in a light JVM to the Web. Kotlin does not. It provides interop to the JS APIs as well as its own tech, but it's not meant to take your Kotlin code and immediately run it on the web (which is an awful, awful idea). You're still meant to write your browser specific code, your android specific code, your x86 specific code, etc. In any language you want, even! Write it in Kotlin/JS, or let your typescript consume the Kotlin/JS bindings. However, you can have a common base that'll work everywhere.
> For native, Graal is a very cool way forward benefiting all JVM languages (as well as scripting languages, its polyglot features are insane).
Graal is an extremely cool project, but with different goals. Write once, run everywhere is a lofty goal, but it only works on very similar platforms (Windows/Linux/OSX). Kotlin has taken a Write once, specialize what is needed approach.
> even went as far as porting Jetpack Compose to work on iOS
Well, Gluon promises the same for JavaFX apps and there is a sample app actually downloadable from the AppStore.
> j2cl still brings in a light JVM to the Web
Not at all, it compiles to very optimized Javascript. Oh, and I forgot to mention that there is also teavm, which is not a VM contrary to its name -- this latter transforms java byte code so it works with guest languages as well.
Swagger + OpenAPI generates data classes for you, and maybe a Retrofit/Ktor/Whatever interface. It does not handle repositories, data fetching, caching and combining, it does not handle a SQLite database.
Which dependencies ? If you already have Android devs, on the iOS side it adds a single swift package, and similarly so on Android.
> It does not handle repositories, data fetching, caching and combining, it does not handle a SQLite database.
right, but you can use that to autogenerate all those things (have done it before) with a few additional tools (code templates) and have it all (repositories, fetching, caching etc) automated (there is a limit of course, combining might be a bit hard in that case)
this is really useful though because now you can deploy to more platforms in their native languages using idiomatic code, and switching to newer techniques, e.g async/await can be done instantly just by updating the source template which any team can download and compile themselves
> Which dependencies ? If you already have Android devs, on the iOS side it adds a single swift package, and similarly so on Android.
for ios, its including basically the whole kotlin runtime and additional support (kotlinx-datetime, etc) in that single package (xcframework), then add a lot of data classes and things start to add up... for us its one of the biggest single dependencies on our ios app
The thing is, they're all optional. You're never going to use any of these features if you don't need them. Your code can stay as a nested list of calls. But put them all together, and you can have code that is super explicit about what it needs to do, without having to re-pass things that are already there.
> Do languages really need new features every N months to stay relevant?
I think a fixed N month release schedule is much healthier than what Java did before, which was wait until everyone was on the bus in order to ship, which resulted in multi-year delays.
No, but fortunately Java doesn’t do that. They have long running projects, when one is nearing completion it will be put in preview in the upcoming release. No rush to make it into anything, it’s ready when it’s ready. (Which should be copied by the rest of the industry as well)
Depends. Are the features making things better, or just more complicated?
Even if it makes things better only for, say, 10% of users, but doesn't make it worse for the other 90%... the users will take that every N months for as long as the language authors can do it.
No, if you are targeting a different platform you can't use JVM libraries.
If your target is JavaScript, you can use JavaScript dependencies (sort of: they won't have any type bindings so you will need to code then yourself) but you can't use any JVM libraries on it.
As other said, yep, you do not get the Java ecosystem if your target is native executables (or JS). there are alternatives like kotlinx-datetime, kotlinx-serialization, the kotlin stdlib. However, if you know you're going to stay on a JVMable target, feel free to not use Kotlin/Multiplatform, but regular JVM Kotlin libraries
IIRC the main appeal of CoffeeScript was syntactic sugar like lambda expressions etc that were missing in ECMAScript 5.
I think ECMAScript 6 made most of the appeal of CoffeeScript obsolete
When CoffeeScript came out, I vowed never to write plain Javascript again. I kept to that vow for a couple years, but eventually broke it when ECMA 6 came out. Really the only thing that put real technical justification behind CoffeeScript was the double arrow function, and maybe the neat class syntax. Beyond that CoffeeScript is just prettier. Even though I was in charge of choosing the technologies, you got to skate where the puck is going, and the puck was clearly not staying with CoffeeScript.
ECMA 6 copied all the good parts out of both CoffeeScript and jQuery, effectively obsoleting both. Modern JavaScript is almost unrecognisably different from what it used to be, and that's a very good thing.
"Our codebase is in CoffeeScript" tended to draw grimaces for years before Typescript came around.
And no, they serve totally different purposes. Coffeescript tried to make JS syntax and variable scoping behavior non-shit, while Typescript adds static typing while changing very little about the core language syntax.
It was a thing for a hot minute in the early 2010s, before ES6, TypeScript, and the React/Angular/Vue trifecta came along and solidified what JavaScript would be from ~2015 onwards.
It was the default for a while for Rails apps and Wiki tells me GitHub & Dropbox adopted it before moving to Typescript. I think for Rails shops it was popular and there was a brief time where it looked like it might become the thing to do on the front end. But I don't think it ever got the interop with existing JS right.
Ultimately, improvements to JS came along and took the wind out of CoffeeScript's sails. Then TypeScript came along and killed whatever interest remained.
Don't forget about WASM as another platform; it's coming as well. An experimental version actually ships with 1.7; it's just a bit unstable and under documented and very much a work in progress.
I think Oracle is catching up slower than Kotlin has been evolving in terms of new language features. Most of the stuff they add to Java (including most of the stuff they are talking about adding), Kotlin has been doing for quite some time. Kotlin is pushing out minor releases about every 3-4 months and major ones pretty much every year. Basically, they do 2-3 minor versions in between major ones. The pace is relentless.
If anything, Kotlin could use an LTS release because it's actually getting hard to keep up with the ecosystem.
A slower pace might be helpful with that. The main issue with frequent releases is that many libraries take weeks or even months to update and don't necessarily work well (or at all) with newer Kotlin versions. I've had repeated issues with e.g. code generation plugins requiring specific version of Kotlin breaking because some other library suddenly requiring something newer. So that then starts blocking a lot of library updates. We've actually put some effort in unblocking some of this for some of the dependencies we have by creating pull requests.
But I'm excited about the next 1-2 years. I expect Kotlin native to stabilize and grow beyond just being a thing for IOS. I also expect wasm support will become usable in that time frame. I hope to be able to use it with WASI for edge networking or serverless stuff. And maybe even some command line tools. IMHO Kotlin has potential for data engineering as well. There is actually jupyter support for Kotlin. And some machine learning frameworks. It's becoming a proper full stack language.
Yes that's right. In fact, Kotlin really works well with the IDE. But they didn't spend as much time in creating a language with a good and sound theoretical foundation. This works in the short time but shows its flaws later. Java is a bit better here (but quite slow though).
So yeah, I can see Java potentially overtaking Kotlin.
Do you know of any good backend web frameworks for Kotlin? I would wish for something like FastAPI for python. Kotlin may actually be a great fit for a service I want to build and I hadn't really thought of it as an option until now.
If you want something old and battle-tested, Spring Boot works just fine in Kotlin. I found the extreme OO design kinda off-putting, but once I got over it I had a great time with it.
KTor [0] is the 'native' web framework for Kotlin, and there's also a full-stack framework built around it that just hit version 1.0, KWeb [1].
Well I care more about simplicity and easy to develop in rather than battle-tested. Something like the Javalin or http4k would probably suit me the best.
Of course, I have checked Ktor before, but I don't know if I particularly fancy the way they are structuring stuff.
My main issue with the java ecosystem is that it's way to enterprisy for my taste. Everything is so unnecessary complex and hard to reason about, but I will take a good hard look at Kotlin before making my decision. The thing is that I am really interested in the native compilation that Kotlin offers that would be very beneficial for me and the only reason behind picking Python otherwise would be that it is a nice language and already installed on the linux environments it will run in.
Basically I will have a big api and drop (preferrably) a single binary to some machines that will talk to the api. These machines will generally be outside of my control. I have looked a bit on Rust but it seems a bit too low level and hard to work with. I have looked at Deno because it can compile down to a binary but using javascript for this project seems like a bad choice. So I chose Python at first because it seemed easy to get going with, had great tooling and is already installed in the environments I will be dropping a script in.
Hard to imagine anything less "enterprisy" than http4k. Zero dependencies, totally modular, and can easily produce a single binary that contains your web app and the web server itself. No Spring, no Tomcat, no app servers necessary. Install a reverse proxy in front to handle HTTPS. Same goes for ktor.
A few years ago, I used dropwizard for both a service that ran locally and for the cloud backend at a startup. Kotlin meshed very well and we never encountered any issues with either. Also just worked on a project that used micronaut which was less mature and not very intuitive, but did support Scala and Kotlin (a goal in that project).
That this has 5 different answers in 30 minutes is the problem I have with the Java/Kotlin ecosystem. There's just so much to figure out before you write a line of code.
I filed an issue for Scala in 2009, that was answered like "sorry, this particular Java code cannot be used in Scala". In 2012 it still wasn't fixed.
I cannot find the issue now, but I remember I was trying to use gae-mapreduce-java library (built on top of Hadoop interfaces). It couldn't compile with Scala.
The biggest advantage of a statically typed language over a dynamic one is the tooling. Refactoring statically typed code, after working with JavaScript for a few years, feels like magic because the tools just make it work
I've found that migrating all your trunk code (data and infrastructure classes) to kotlin is the biggest win, and you can leave your old leafs (fragments and view models) in java if you want do a low risk migration. If a view isn't broken, you don't need to fix it, but getting nullability annotations in your data models and REST commands is a huge win for newer views and business logic going forward.
I'm currently working on a project which has both Java and Kotlin and I really have to say that I like working on the Java parts much better than on the Kotlin parts. I find coroutines a really strange and leaky abstraction (and the prevalence of suspend methods in libraries which you have to wrap all the time just to call them synchronously is really annoying).
With streams and the var keyword, Java is also not that much more verbose anymore than Kotlin and the code completion, error detection and refactoring capabilities are much better in Java. In Java I can also be sure that if I directly access a property on a class, there will be no side effects or expensive operation while if I use a getter, there might (and I dont have to write them either due to code generation or Lombok). So the parts where Java is still more verbose actually add clarity (and again, due to the IDE, you rarely have to type any of it): I dont really get why I would leave out the explicit types in the source code, only to be added again as non-editable, weirdly positioned text by the IDE (which is not there if just wanna have a quick look at the code on GitHub).
Sure, but the one thing Kotlin has that makes me never look back is null-safety. Java has optional and non-null annotations and whatnot, but you have to be vigilant and put the right annotations everywhere. Kotlin you get this for free.
The extra sugar on top is super nice too - listOf, mapOf, x to y, apply… I think it just makes code that much cleaner. None of these are make or breaks but together they work amazing. A lot of what I work on professionally is still on Java 8 or 11 so I don’t get any of the cool features like record types.
Most of the OSS I do is Kotlin bedsheets I just enjoy writing Kotlin. I don’t feel that way with the older versions of Java (I’m starting to with the newer ones).
While I also love many things about Kotlin, the one thing that always sticks out like a sour thumb is error handling.
While Javas checked exceptions had a lot of problems, at least there was a way to declare the output (errors are ouput) of a function on a type system level.
With Kotlin, that's just gone. You can fiddle with Result type (or make your own), but you lose a lot of the ease of "bubbling up" errors.
How do you handle errors? (I wished Kotlin had error handling like Rust, which is the best that exists, imho)
Most frameworks give 400 bad inputs. If the client gives a null but null is not allowed in the type, it will auto respond with 400 before it ever invoked the handler.
Java spring does the same thing: if you use an unboxed type (int instead of Integer) and the client passes in null, the handler will never be invoked.
But if you have an evolving API, you are back to what was asked. Either you are a bit of a jerk to all of your existing clients, or you have default values at the boundary.
I've found myself with this a lot on "progress" data classes where I will be building up a set of data over several expensive calls. I /could/ make a new type per current state of that, such that I never have nulls. I /could/ make it so that every field is Optional. Or, I could work on a convention that fields are filled out in order, and after the first null, nothing is available. In many years, this has not been where null pointers hit me.
To add to this I had a specific scenario in mind. At @current_job they bolted on a immutable struct library and wrote validations. We are responsible for sending out renewal notices and we get the renewal price from another system. In certain scenarios we were getting back a null price and our validations dutifully caught the null and threw an exception.
Theoretically everything worked. However, the end result is (1) the customer didn't get their renewal notice and (2) we got a validation error instead of (maybe) a NPE somewhere. So what exactly are we accomplishing here is my broader point.
To be honest, this is more of a question about how best to handle errors in asynchronous event handlers (not handlers marked as async, I mean like send an email at xyz time). Imo best way to solve this is to get notified of an error in sentry, be it an NPE or validation error.
In a case where the client expects an immediate response (http GET) getting “400 validation error: foo is not allowed to be null” is a lot more meaningful than “500 Null pointer”.
In general I try not to model invalid states - less mental overhead (no one has to tell you xyz can’t be null it just cannot be null).
Ofc this is a matter of opinion and the lines get blurred as soon ad you move stuff to runtime.
I believe the standard practice (as popularized by Google) is that all fields are optional. This allows you to deprecate fields in the future while still support older (non-updated) clients.
Yeah, my question is more about what you do as a consumer. How do you get back null safety if every field in the response is optional? Even moreso, in a SOA situation where 90% of what you work with comes across a HTTP boundary.
I'm not sure I understand the question. If you have only Optionals and Null does not exist, a NPE is impossible. The Optional type forces you to handle the empty case, so null safety is enforced by the type system.
You handle it how you would have handled fixing a NPE which shows up in production. Except now you handle it before an NPE ever shows up because the type system forces you to.
I think coroutines is probably the best implementation of cooperative multitasking (async/await) that is is available in any language: They build on structured concurrency and thereby allow to prevent a few common concurrency problems like runaway tasks. You can run them on different threading systems, like UI threads, threadpools, etc. And they default to run the continuation on the correct thread.
However as any async/await implementation it will obviously still have challenges. The "colored" world of functions means users need to know the differences between suspend functions and other functions, and using something wrong can lead to performance issues.
One thing to note is that with the upcoming of virtual threads (Project Loom) in Java itself, the need for using coroutines might become much smaller. You might just end up using them for UI work, and everything else could use virtual threads. That could simplify a lot of things.
Loom will just slot into co-routines without requiring many (if any) code changes. It's still going to be nicer to use co-routines from an API point of view and they'll just use the loom stuff underneath pretty much transparently when it is available. A virtual thread is basically just yet another thing that you can wrap with a co-routine. There are many such things across the jvm, js, and ios-native platforms that are supported via Kotlin already.
And since it is API compatible with things that are already supported by co-routines, pretty much all you need to do is change your custom co-routine contexts to be backed by virtual threads rather than actual threads. This should just work even without explicit support for this in the co-routines library (it's just another thread pool). But they obviously will add explicit Loom support as well as it makes sense to make co-routines be virtual threads pretty much always.
When that ships, all current kotlin code that uses co-routines will be using virtual thread on a Loom capable jvm. It already has structured concurrency and all the rest so all of that will continue to work. And some of the blocking Java stuff that you currently need thread backed co-routine contexts for, will stop being blocking so you can stop doing that. But it will still work of course.
I guess you could "slot loom into co-routines", but the niceness of loom is that you don't even have to use coroutines. It could just be regular "blocking" Kotlin functions which run on virtual threads.
If you already use Kotlin coroutines - fine to continue to use them. But I imagine for a new project you might want to opt to build on virtual threads instead of coroutines.
> With streams and the var keyword, Java is also not that much more verbose anymore than Kotlin
I have no experience with Kotlin yet, but I recently did some Java after years of js/ts, and was nearly driven mad by constantly having to convert different kinds of collection. String[], Array, List, Iterable, Stream... and every library expects or returns something else, so you're constantly converting these things.
Any of them would have been perfect if only it had been supported by everything, but because of Java's long history of constantly inventing newer and better ways of doing things, libraries written at different times support different kinds of collections and you constantly have to convert them.
I agree to some extent, however, IDEA often helps you with that (e.g. by converting arrays with Arrays.asList(array)). And I have to disagree: Any of them would not have been perfect. An array is sometimes significantly more performant and requires less memory than a list.
In the different collections, you see a history of 20 years of developer experience improvements coupled with an almost religious emphasis on backwards compatibility in the language and standard library.
In every (long term) JS/TS project I worked on, about 20% - 50% of the development time went into upgrading libraries and keeping everything running on the current node version. It was maddening. Stuff like the different types of collections are a very small price to pay, IMHO, if you can be sure that your current Java project will with very high probability also run on a current JVM 10 years from now.
> Any of them would not have been perfect. An array is sometimes significantly more performant and requires less memory than a list.
That's actually why I prefer List, because a List is an interface and can be an ArrayList or another type of List and I don't care about the implementation, as long as it's a List. But Array is an array that's not a List, and Iterable is also an interface, and I think a List is also an Iterable, but I'm not sure, and I suspect not every Iterable is a List. And then there's Stream which should have been a set of convenient functions that are part of List or Iterable right from the start, but they're not. And what the hell is a Spliterator and why do I need one to turn an Iterator into a Stream?
I understand that there are reasons for this, and I totally agree that the js/ts dependency situation is far from ideal, but it's still maddening to have so many different collection types, when js/ts just has an array that's not even an actual array, but it still works fine, and all the new stuff just gets added on top of it.
One of these days someone should invent a new programming language that finally gets all of this right once and for all, but I bet people will find ways to improve it again.
> I understand that there are reasons for this, and I totally agree that the js/ts dependency situation is far from ideal, but it's still maddening to have so many different collection types, when js/ts just has an array that's not even an actual array, but it still works fine, and all the new stuff just gets added on top of it.
It "works fine" for basic cases but it doesn't give you anything like the same capabilities. JS/TS have no easy equivalent of array or stream, anything you could write in js/ts you could write in Java by only using ArrayList. Java's collections library is big and complex but almost everything that's in there is there because it has a use case, and while it's showing its age now it was well designed for its time.
> One of these days someone should invent a new programming language that finally gets all of this right once and for all, but I bet people will find ways to improve it again.
Your best hope is a language with Haskell-style typeclasses where you can not only add new implementations of existing interfaces, but also retrofit new interfaces onto existing implementations. No library is going to be perfect from day 1, and a big part of the reason why Java Stream is awkward is that it had to be retrofitted into the existing collection library.
I'm curious what libraries you are dealing with that are so opinionated on what collection type you send to them? In my years of working with Java, I think I see List. And... yeah List. That is about it.
I have had some internal teams try to use Iterable or arrays, thinking they needed to be optimized. Almost without fail, those are from teams that stall out and never actually finished what they were doing.
I have seen case studies of giants that actually needed to optimize down to arrays or buffers, but this is often not the case. I'd imagine unless you are trading or gaming, you can get more than enough mileage out of List. (Specifically ArrayList. LinkedList is usually a sign of premature optimization without having actually benchmarked what was running.)
In your own code you should always use one of collection classes, usually Iterable, Collection or List, depending on which features you need.
Stream usually is not used other than for call chains. Like list.stream().map(...).toList();
I write Java for many years and I can't really say that this was source of pain for me. I agree that streams could be implemented with better ergonomics, but Java designers wanted to provide us means to use parallel computations with one extra word, so here we are. I've yet to find a place where I'd want to use that.
I used collection classes in Java 1.4 and I'm using them in Java 19 and I don't think that anything changed in that regard. Collections are the same.
This sounds like you are trying to shoehorn asynchronous kotlin code into synchronous Java code. Which would be doing it wrong. The problem is trying to make asynchronous code synchronous: don't do that. The whole point of asynchronous is to do it end to end and isolate the remaining synchronous bits and pieces that you have on separate threads so they don't end up blocking all the asynchronous bits and pieces that you have.
Use a proper asynchronous framework and then the only thing you need to worry about is avoiding calling synchronous code on your main thread (i.e. dispatch it to some thread pool backed co-routine context). Not that hard. And you can get rid of a lot of that stuff by gradually switching to non blocking versions of whatever you are using.
If you are exposing class properties without accessors in Java, that's not necessarily a great thing. Especially if your state is non final (i.e. mutable). In Kotlin, you'd use vals (or vars if you really have to) and by default they just behave like they have getters/setters. But you don't have to spell it out. And you can override the getters and setters. Just like you would in Java. It's just the distinction is not there. It's basically a less hacky Lombok.
The weirdly positioned text that your IDE adds are called hints and you can turn them on or off as you please. They are there to help you. Type inference is a nice thing: it means you can read the hints without having to spell out what is what. Java has type inference too but it's a bit more limited and more verbose. There is no uncertainty about what the type of anything is in either language: exactly what you specified (but just once in Kotlin's case).
> I find coroutines a really strange and leaky abstraction.
I've only used Kotlin on Android, but from what I remember co-routines are not necessary to use. If you don't like them, then don't use them.
Kotlin has a number of advantages over Java. The biggest of which is built-in optional typing. It's also really nice that everything is expression instead of a statement. Library functions like `let` also make code a little nicer to write. And stuff like data classes and better property initialization are icing on the cake. In my opinion, you can write Kotlin exactly as you would Java, but the development experience is much more polished.
Those examples seem very biased; often the Java version does not use a more concise method that's available, or bloats the code by not importing a static method.
In practice, the return type is often obvious. You can write:
val foo = new MyReallyLongUglyFactoryClass()
instead of:
MyReallyLongUglyFactoryClass foo = new MyReallyLongUglyFactoryClass()
And you never have to use type inference. If you have a method where the return type isn't as obvious, you can always annotate it explicitly:
val foo: Int = doSomeThing()
Do people exercise judgement about when to make the type explicit? Eh, depends on the team. But if you combine type inference with established conventions in a particular codebase (e.g. I/O calls always return IO[Foo]), you will rarely be left wondering what the type of something is.
Yes but that isn't real code. If you see something like:
> var conn = openDatabaseConnection();
Are you actually confused about what conn represents? Does it matter what the exact type is, if you already know what it is and what you can do with it?
I mean, you could just search for the method called, if you're REAAALLLLLYYY averse to using any IDE or editor of the last 10 years. Which would be an odd choice to base language decisions on.
No compiler there so the compiler can't tell you the type. No IDE there so the IDE can't tell you the type. You're at the mercy of colleague(s) not to write code like var request = service.call() or, worse, var b = getResult().
I prefer inferred types when available. Then an IDE and compiler can get together to provide further details when needed. Honestly f: MyStupidInterface = myStupidMethod(); doesn't tell me much more.
practically all modern strongly typed languages are adopting or already had type inference from day one, allowing you to do things like var. They give up nothing in terms of strong typing to do so. Forcing people to write manual boilerplate does not equal professional, what a strange take.
Fundamentally, this is a story of technology getting better (type inference in compilers) so humans can do less work. We're not pushing the work to some other human place. We're not losing anything in safety, and we're gaining in readability, boilerplate and expressiveness. Its progress!
The era of not knowing the difference between static typing, strong typing, and type inference is past. I'm the sort of professional who likes to learn computer science.
> you're not writing code for compilers, you're writing code for people
i agree, thats why i don't want to clutter my code with annotations designed for the compiler, not humans. Type inference is a _good_ thing for readability.
You can just the type hints in the IDE for bad code like the above example. But glancing through my code, that is never an issue in practice because code reviews should have caught the poorly named variable and method.
Since the actual size of the code base isn't an issue in the modern world, I personally like that the Kotlin ecosystem discourages the use of esoteric names and non obvious abbreviations. Once you write and read enough of it you stop making poor choices.
I don't find coroutines that helpful, but the syntax sugar and standard library in Kotlin is pretty awesome. The Elvis operator alone is worth the switch. Say you have some container with 3 levels of nesting. In Java, you have to null-check every level vs. 3 "?." dereferences.
In theory this is possible to approach with annotations but I found it hard to keep up in a large codebase.
Records ergonomics is terrible if you want to replace data classes with records, even if immutable is OK. You need to write builders. You can't really write code like
Withers can help with that, but they're not even in any kind of experimental shape right now, so we have many years to wait for it.
Right now records are only fine for very simple use-cases like Point(x, y). Or if you want to write or generate builders. But at this time you don't really save anything, if you can generate a builder, you can generate a class as well.
Yeah, I don't like JPA because of lack of support of immutable types (records or my own classes that don't have setters, only constructor).
If you have data class with more than 5 fields then you have it wrong. Builders are like lombok and like field injection: hide poor class design.
If using a class hurts, it is badly designed and should hurt until it is refactored/split up into consumable parts.
I use records extensively, but those are in most cases converted classes which were small and immutable. JPA being one of the exceptions (a stuck in the past spec)
I can't imagine other way of dealing with database rather than using a single class per table. Projections are a way to optimize some niche queries which are too slow otherwise.
> I find coroutines a really strange and leaky abstraction (and the prevalence of suspend methods in libraries which you have to wrap all the time just to call them synchronously is really annoying).
I think the point is to be calling them asynchronously. Unfortunately async programming is kind of contagious and difficult to shoehorn into sync stuff but if it’s written asynchronously there’s usually a reason.
Interesting that they were able to quantify the reduction in source code length very precisely (11%), but when it came to the regression in build times ... nada ... just talk about how they plan to mitigate the issue.
We don't have numbers around this because the numbers are actually really hard to make sense of.
This probably sounds a bit weird, and it surprised me at first.
Unfortunately measuring build times is extremely noisy: different people build different things. They do so at different times. On top of it we have incremental builds (so only some part, depending on the modularity and some external and in-house optimizations, gets rebuilt). The incremental builds depend on cached artifacts that need to be downloaded, and many more complications.
The result is that if you look at the graphs the values jump up and down based on time, days, moods, network, and many more causes, plenty of which we have no idea what they are.
I have not yet seen a successful attempt at cleaning this data up so that some number would be worth publishing. We could try building some toy example that we separated. But that won't be useful to guide our work on build times, nor do I think that it will be valuable to share with the community.
> the numbers are actually really hard to make sense of.
1. Then how do you know builds are slower?
2. How will you know that the things you are doing to improve build times are working?
> jump up and down based on time, days, moods, network, and many more causes, plenty of which we have no idea what they are.
3. Performance being highly inconsistent is actually a (significant) performance problem itself and worthy of reporting, analysing and quantifying. (ranges, averages etc.)
> not yet seen a successful attempt at cleaning this data up so that some number would be worth publishing.
4. Not sure why you think they need to be "cleaned". Again, numbers being all over the place is likely an important data point in itself, an even if it isn't the raw data would be valuable.
> We could try building some toy example that we separated.
Why? Just do a clean build on a local machine. Report real and user+system time. (man time). Repeat.
1. There's some trend lines, or you can see a Kotlin module during build taking a lot of time. However, we can't tell how much of it is due to Kotlin and how much as an artifact of optimizations such as [1] that we work for Java and not Kotlin for now.
2. We have more specific metrics for parts of the build that we know would improve. For example, migrating annotation processors to use KSP instead of KAPT makes modules build faster. (This doesn't mean we can easily expect a different trend line in the top level graphs since in the meantime the amount of Kotlin code is changing.)
3. I'm not sure what your experience is, but according to mine it will be a "nice to have" but un attainable or at a cost of real user improvement. For example, if a lot of people build at once network caches might be slower. How does one remove that noise? Up the caches - that's more money and other updating issues; try to take it into account in data? maybe, but that's one of many issues (going back to the next point)
4. The commenter asked for numbers on builds. I don't think a graph that's jumping up and down due to the complexities and optimizations of Meta' build architecture is useful to anyone outside Meta. I think deducing results about Kotlin build times from it would be deceiving.
> Why? Just do a clean build on a local machine. Report real and user+system time. (man time). Repeat.
This number is not stable. Even if you shut off network caches and other similar things. But more importantly - this number is not useful. Our users rarely have that experience. One of the common sub goals we have when dealing with build times is to minimize the times someone will have to do a clean build.
We have a consistent braces style, so the lines that are removed are rarely those.
A lot of the saves come from `?.` replacing null check chains. Many more from the shorter constructor and field initialization syntax (you can get a bunch of things in one short statement). A bunch more from usage of standard library lambda taking functions (`first`, `single`, etc.). Some more just comes from shorter lines due to less explicit types. These are all more some guesses due to conversions I've seen, and not the result of accurate analysis.
We also use very little Java streams. A combination of Java 8 arriving late to Android code, and the preference to avoid extra allocations and inefficiencies streams can cause for shorter lists.
I've seen the same on my own converted Java code. Less lines of code. But you also get lots of a really short lines. And some formatting actually spreads things out over multiple lines for readability. E.g. I use intellij's build in "put arguments on separate lines" a lot. Especially with named arguments, this is just nicer to look at. It's the same or less code but more lines. But less dense code.
A more interesting metric might be simply the byte size of the source files. I would expect that to be slightly better than 11percent. Maybe closer to 20-25%.
A nice, simple kotlin left-to-right access deep into a nullable nested object tree can quickly be four lines of java for each and every ´?.something´, for as many of them as fit into your preferred line width. In java, this often leads to either skipping more null checks than you really want to skip, or calling getters more often than necessary.
Kotlin might seem a little weak to someone returning from a scala deep dive, but where it really shines is in creating a large overlay between the convenient path and the pedantic path. It removes many "in the small" tradeoffs that you just take as a given in java. It's the "better java" that groovy was not.
If you have more than 2 levels of nested null-checks I would wager you are doing something fishy. You should probably go with mapstruct or similar libs (which are absolutely cool and a must for data conversions).
On my fishy scale, requiring translation between different data models would by pretty high up. And how would it help anyways? Absence can be a perfectly valid state and alternative representations of absence like scala's Option seem pointlessly ceremonous once you've worked with a syntax that does not completely suck at dealing with null.
It's too bad other IDEs (like VSCode) have only a primitive support for it. That means Kotlin is only ever usable with an IntelliJ license, and forces one to use this particular IDE.
If i were to do JVM related stuff, it'd use Kotlin without hesitation
That language, just like with Swift and Haxe, they remind me of the good old Flash/ActionScript 3, i loved that language so much
It's imo the best form of a programming language one can come up with, very easy to learn, read and write
I wish kotlin-native story was better, it's a shit show, super slow to compile, and they decided to go with Gradle... it is on the same level of confusion and bloat as CMake, a pure mistake
What's the story with Android and iOS cross development using Kotlin? Any major benefit over Java (which used to be a thing at least in the days of j2objc)?
KMM (kotlin multiplatform mobile) just hit Beta status. Its a really unique value proposition compared to other cross platform options in that it doesnt run via a VM (either Javascript or e.g. Mono for Xamarin). It compiles to native LLVM on ios, and as such you can write your UI natively if you want.
I was holding off on KMM before, but I've started looking lately and its extremely promising. There is still a lot of ecosystem that needs to be built out (e.g. you need to find cross platform / pure kotlin implementations of URI or Color), but it is shaping up to be the leader in the space IMO.
Why would anyone use it if you can’t take advantage of the vast Java ecosystem? Why would I choose it over Graal for example, which has much bigger backing, stable and is language-agnostic.
You can take advantage of Java in the next layer up, but you lose out on sharing that portion of code/logic then.
There are actually 3 layers in play for each platform: The pure kotlin shared layer, the "native" kotlin shared layer, and the native-native layer. That second layer (the native kotlin shared layer) is platform-specific kotlin. So on JVM platforms thats the normal Kotlin you are used to, and as such it has access to Java. On iOS that second layer is Kotlin/Native, and you actually have access to native _bindings_ to the native layer (i.e. I can call into UIKit, but in Kotlin code). If you put your "native" code in the second layer instead of the native-native layer (which on iOS is Swift/objective-c), then you can move that into the innermost layer if/when it makes sense over time, and the frontend is none the wiser.
Here is a good visual and explanation (the rest of the presentation is a good overview as well, but I think this slide is the best part of the video): https://youtu.be/2yd6rVJdICU?t=1749
EDIT: I should also note that nothing prevents you from creating "glue" bindings in the pure kotlin layer using either expect/actual or an interface, and then reifying that using some JVM thing in the second layer, and writing the other platforms more from scratch to fulfill the contract.
just a note for those who've never used kotlin native: its generating obj-c code when compiling for ios, so you cant use any swift-based apis that arent exposed to objc from apple
uikit isnt going anywhere for a long time probably, but its an important caveat
Right, I forget to mention that. But if you are in the cross platform space thats just how they all work (that I've encountered at least). The difficulty of consuming Swift in Objc vs the other way around means that lots of iOS libraries are Objc based, but Apple is starting to signal that it might be over sooner than later as they begin to introduce new Swift/SwiftUI-only subsystems. Or maybe they have an ace up their sleeve with exposing those in the Objc space. Doubt it.
EDIT: and a nitpick. Its not generating any objc code. Its generating a binary which is exposed to swift using the same mechanisms that objc libraries use. I.e. it compiles to a native binary (an xcframework or framework, I forget which). It doesnt transpile.
> Its generating a binary which is exposed to swift using the same mechanisms that objc libraries use. I.e. it compiles to a native binary (an xcframework or framework, I forget which). It doesnt transpile.
right, though the native library (xcframework) exposes its interface as objc objects (.h header files), since swift only knows how to read c and objective-c modules afaik...
Well there is kotlin-native which allows you to write kotlin libraries that compile to IOS and Android. Which you can than link to objective C or flutter based UIs. Or even react native. That allows you to share a lot of code between different platforms. A growing number of Kotlin libraries are multi platform meaning you can use them on IOS, the JVM, and in browsers.
Java doesn't have that and it's kind of an increasingly dead language for mobile development. Some older android projects still use it. But Meta is late to the game of migrating away from it. Many companies did that years ago and the vast majority of new Android applications is using either Kotlin or Flutter/Dart.
I have good hopes for Jetbrains extending the jetpack compose/compose desktop/compose web ecosystem to IOS at some point as well. That would create some interesting possibilities in terms of targeting just about any platform with kotlin from a single code base. It's a logical next move for them and they've been laying the groundwork with their multi platform compiler strategy for a while now.
the tradeoff for high level languages is supposed to be that you gain a lot of expressivity (requiring fewer lines for a developer to express their intent) and you lose performance because of the multiple layers of abstraction required.
10 million lines of code for an Android app, or family of apps, feels like the tradeoff has definitely not born fruit.
operating systems written in Assembly have far fewer lines of code than this.
I think the point stands: the amount of complexity involved in each little piece of app is huge when taking into account dozens of countries and customizations by city.
If it still doesn't seem worthy of 'thousands of engs', imagine breaking down every point in the list to the level of detail the author broke down payments. And then apply the logic in the top comment mentioning backend systems + teams to support other processes (and internal tools needed).
interesting how much of this is glue -- like if mobile had better support for inter-app handoff, these flows could be entirely delegated to external provider's app (paypal, venmo, support saas)
(though hard to generalize to other parts of the app, bc payments is inherently glue-y)
constantly wonder what kind of support layer would make UX integration user-friendly, but also developer-friendly
it really is. a sibling comment of yours points out some info posted by a former Uber engineer about why, and even considering that, 10 million lines seems extremely high.
Windows XP is smaller than the Facebook app for Android...
I'm interested in exploring Kotlin for backend development.
But, most Kotlin projects, articles and anecdotes center around mobile apps.
I imagine companies hiring Kotlin developers would mostly get applications from people with mobile dev experience
There's very mature and widely used Kotlin support for Spring Boot. They've been actively supporting Kotlin for years and it's a well documented and well supported option in that space. Same for many other Java frameworks (e.g. Quarkus, Vertx, etc.). The reason is that it's so easy to integrate just about any Java framework from Kotlin and make it nicer by adding a few extension functions, turning builder soup into more readable Kotlin DSLs, getting rid of all the getter/setter madness or silly hacks like Lombok. I've converted a fair bit of Java code to Kotlin. You almost always end up with better code. Certainly less of it.
The notion of Kotlin being a mobile only thing emerged out of the happy accident that the need to get rid of Java was simply felt so deeply in Android that developers were all over Kotlin even before it was released properly. Backend developers waited a bit longer.
As a drop in replacement for Java it made a lot of sense there. Google at the time had the whole platform stuck on Java 1.6 while they were engaging with Oracle in the courts. So a lot of the nice stuff in 1.7 an d 1.8 was not usable and forget about all the stuff that was added to Java and still is being added. Most of that you could get with Kotlin right then and there. So, people jumped on it.
For the same reason, people have been using Kotlin with Spring since about the same time. Google and Spring made it official around the same time as well with Google outright labeling it as the preferred language for Android (while not cutting off Java) and Spring just adding an enormous amount of Kotlin specific features and extensions starting with Spring 5 and Spring Boot 2. At this point both have documentation for both Java and Kotlin. There are really no downsides to using Kotlin on the server. You can do everything you could do with Java and you gain access to a lot of easier to use stuff than the Java equivalent.
I've been using it since before Spring supported any of Kotlin. Worked fine then and it only got better since. The language alone is worth switching and once Spring started actively supporting it, it only got better. I write asynchronous co-routine code with Spring by default. Mostly it just looks exactly like synchronous code. The only way you can tell is that my controller functions are suspend functions. Spring takes care of the rest. That makes everything easier: more readable logic, error handling, etc.
The only thing that prevents me from using it is the license that shows up during installation. Has anyone read the license? The same applies to Dart (Flutter).
why does navigating to this document, open a new tab, close the old tab. The result being there is no history that the "back" button (FireFox here) can get to. Seems like a lot of trouble to go to just to annoy me.
“In recent years, Kotlin has become a popular language for Android development. So it only makes sense that we would shift our Android development at Meta to Kotlin as we work to make our development workflows more efficient.”
I like Kotlin, but this was pretty funny to me: I imagined walking into a meeting and trying to tell colleagues we needed to move to X because it was popular, then yeet out the ole “efficient”, mic drop & moonwalk out
Happens so much more often than you think. Have actually seen it with the exact same language (Java->kotlin) on an existing service. I don’t really recall any valid reasons being given for the switch (better support for concurrency etc). I think often times managers allow this bc they don’t want certain engineers to get bored and leave, which is odd to me since who knows why/when they will leave and they won’t take the services with them.
It happens all the time. I remember when AWS wall all the rage my boss came up and told me we need to use S3. Why? "Because everybody is using it!" I tried to reason, I did a cost analysis - all for no avail. The same boss a few years later: "Why are we paying so much for storage?!" He apparently forgot he insisted on it in the first place.
Facebook is primarily a message and photo sharing application but it also has group boards, dating, live video streaming, a marketplace, browser games and probably more features. Then there are all the features for targeted ads, tracking, payment and so on. All of this is available almost all around the world.
How do you implement these features for more than a billion active users in less than a million lines of code? Even 100 million sounds like a low estimate.
Why does the Linux kernel have more than 30 million lines of code?
You could ask if these features make sense. But in the end it is their business decision to make.
Aside from the technical challenges of running a system with such a massive amount of data:
translations (left to right text and layout: https://sy-sy.facebook.com/), different laws depending on jurisdiction; for example privacy/moderation/takedowns, taxes/payment/invoices if you are selling anything, accessibility
If you ever start a company and you have the long-term goal to offer your service in multiple countries I would advise you to launch in at least 2 countries, preferably supporting different languages.
My guess is that it's an extreme case of Conway's law, with many teams that produce mountains of code hidden behind some API. Not to mention codebases provided by external firms, which could amount to a large % of all those KLOC.
I'm interested in how they avoid "Roman empire syndrome", as in owning more software than they can maintain while actively expanding it.
This happens with "everything" apps that have hundreds of features you have never seen, each serving a tiny fraction of the userbase who somehow stumbles on them and justifying the PM/eng resources to keep them chugging along, or abandoned and left to rot until these migrations come along.
How much is kotlin vs high res assets or shipping every experiment to turn them on/off with feature flags? I suspect the language contribution is actually pretty minimal
According to them[0], Facebook's primary languages are C++, Java, and Python, and they're even embracing Rust now. In general, teams have the freedom to choose what languages and technologies they want to use. (quoting from the linked video)
They might've started with PHP, but even that stopped being a thing once they switched to Hack, their home-grown language, ~10 years ago.
Not quite. According to a more recent article, Facebook's PHP, Hack, is still a primary language:
> For business logic and relatively stateless applications, the Hack ecosystem has the highest level of automation and support at Meta and is the recommended language.
On a related note, their Rust usage has grown significantly:
> For performance-sensitive back-end services, we encourage C++ and Rust. Rust is a new addition to this list. There’s a rapidly increasing Rust footprint in our products and services, and we’re committing to Rust long-term and welcome early adopters. For CLI tools, we recommend Rust. This is a new recommendation for this year.
I am pretty sure, people who build Facebook or Messenger apps for Android does not use the app. If you use Facebook or Messenger for more than 10 minutes, you would find at least 2 very fundamentally wrong bugs. I would have fired most of the developer if I were the CEO of Facebook. They are not competent to work at Facebook
Whenever I try to get into another language today, the lack of language-aware editing tools are my main source of frustration - specifically, I expect navigation, refactoring and completion to work flawlessly. I know of no other programming language that puts as much effort into context- and structure-aware refactoring - if another language does one day replace Kotlin, it will need to offer a comparable editing experience.