Kotlin is one fine piece of engineering. It's only too unfortunate that the same Achilles' heel is holding it back as Scala: there is only so much you can do while remaining compatible with JVM and the Java standard library. Actually, it's even worse: Kotlin swore a seamless compatibility with Java. Maintaining compatibility against a moving target has the potential to make things quite messy. An early example of that presented itself just after Kotlin 1.0 release, when Java 8 came out with with new and shiny functional Collections API - incompatible to Kotlin's.
The new Collections API wasn't incompatible with kotlin, it is just you can use the new API if you target Java 6 (which makes sense). But you can use the new API if you target Java 8. So I don't see a big deal here.
The problem is not the compatibility with the new Java API, but with the new bytecode definition. But it is going to have the same problems Java have. The big difference with Java here is that you can adopt new bytecode specifications without using the new Java APIs, or doing some modification in the bytecode generation to "simulate" those new features. And this is the key why it is taking over Android community. You can support legacy bytecode with new features. Which you cannot do with Java.
A problem for kotlin (and java) is the new packaging system. But kotlin is already working on it changing how they package their standard library. So it is even less problem than java.
Quoting: "Sometime ago we introduced kotlin.Stream<T> type, with the simples possible interface – iterator() function – with the idea that we can make it compatible with Java8 Stream<T> type. Currently we seem to come to a conclusion it was a mistake as we cannot fine a way to represent Stream<T> as kotlin type in Java 6 & 7, and then use to Java8's Stream<T> when targeting JDK8. If you have any idea about how to make it work – please share!"
Basically, while Kotlin is more or less a straightforward extension of the Java 6'th Collections APIs, by Java 8's release the two have diverged. When programming in Kotlin, you would normally use its own functional APIs, not Java Streams API. While technically nothing prevents you from using Streams, they don't fully integrate with Kotlin's native Collections, so you're forced to choose one or another.
That more or less what I said, it is not incompatible as you can use the Java stream API if you target Java 8. But yes, it is a pain when you see you have to use the Java Stream API instead of the kotlin Stream API.
Not incompatible but an issue. And they seem to have resolved it. Look at last comment. What you are quoting is from December 14th, before even the initial 1.0 release of kotlin.
Like I said, Kotlin is chasing after a moving target. The issues might be kinda-solvable (even if it requires significantly diverging from Java's APIs), but things inevitably get messier both for the language internals and for users.
Kotlin has an extensive Collections library, which started largely as an extension of Java's, but now it offers much more. In any case, I was referering to Kotlin's APIs, not Collections per se, and it certainly has its own APIs.
> It's only too unfortunate that the same Achilles' heel is holding it back as Scala: there is only so much you can do while remaining compatible with JVM and the Java standard library.
Being part of the largest, most successful, best tooled ecosystem in software is an Achilles' heel? Most people would (and should) gladly take that over any particular language feature.
JVM can run "Hello World" in about 50msec these days. The java guys do care about startup time, you can see if you read their mailing lists that they are constantly trying to defend their startup time as new features come in that add initialisation work. It's a priority.
Still, the reason many Java apps may feel like they start slowly is that they tend to do a lot. The app I'm currently working on starts in about 5 seconds, which isn't terrible by the standards of the space but isn't great either. But the reason is that that 5 seconds involves initialising an entire message queue broker, an entire relational database and an entire web server. These aren't tiny 'embedded' versions either: they're Artemis, H2 and Jetty, which are both also used standalone and have cutting edge featuresets. If we weren't using the JVM then we'd presumably be using some container based solution and starting postgres, some other MQ broker and apache or something. Bringing up such a container from scratch could easily take 5 seconds or more I think.
The JVM will by default use all the memory on your machine. This is an unintuitive default, to put it mildly. The reason is that the JVM can make your software run faster by using more memory. Doubling RAM is easy. Doubling your CPU cores whilst keeping them actually used is hard, doubling the speed of an individual CPU core at this point appears to be nearly impossible. So it makes sense in a technical way. But it does make it hard to judge memory bloat.
Again, speaking about the app I currently work on, I got a support request the other week from someone who wanted to run the app on a Raspberry Pi and was complaining it took much memory. Quick testing showed we actually only needed about 50-75mb of heap and simply telling the JVM to limit the Java heap to that size slaughtered memory usage and resolved the problem. Not hard to check that and configure things for small devices, but it's a knob you can't/don't need to twist when using manual memory management, or GCs designed for mobile/laptop devices where minimising memory usage took priority over raw runtime performance.
Honestly 5 seconds is an eternity when it comes to modern processors. I'm not convinced that it's a norm and I'm still wondering, what really happens, where that time goes?
"initialising an entire message queue broker, an entire relational database and an entire web server" is just abstract words. Initialization of an entire web server is creating a socket and binding it to 80 port, that's what should be done, but what else happens? Initializing a relational database is something like opening a file. May be read journal, rollback unfinished transaction, but those things could be done after initialization.
I use Java and I'm always trying to improve startup time. Last time I used undertow for tiny project, with jdbc to access remote database. Project started in mere milliseconds and it was much easier to iterate. But every time I enable something monstrous like servlets, hibernate, spring or, save god, java ee, it's always 30+ seconds start time. And I always wondered, why that's happens? I can serve millions of customers in those 30 seconds, I can read gigabytes of data from my HDD and parse millions of XMLs.
It's not so much the startup time (which is ~60ms), but warmup time. Assuming you're using a JITting JVM, it's compiling. There's now work on AOT compilation in HotSpot (and some JVMs already have it), but it really doesn't matter for big, long-running server apps, which are currently HotSpot's forté.
I haven't done startup profiling in detail but I'd expect most of the time to go on waiting for IO. CPUs are fast but opening a database, checking disk for queued messages etc is slow. Startup involves querying the database in our app, so the DB can't do that work after initialisation. There's also network traffic and RPCs happening in that 5 seconds too.
Without a doubt also some algorithmic waste in various libraries that aren't optimised for startup time. Startup time is rarely a metric that products compete on outside the consumer space, so improving it is not normally a priority.
And then yeah, finally the lack of AOT compilation. When Java 9 rolls around I plan to try and see how much difference it makes.
Sure. The ability to inspect what the system is doing and interact with it while it's running full-speed is unparalleled, and only pulling further ahead than anything else out there. Just take a look at monitoring tools like VisualVM, or Java Flight Recorder, which is part of the Oracle JDK and free for development use. You can inject and take out code at runtime, and the same monitoring and management API, JMX, is standard and used by everything from the JVM, the JDK libraries, various frameworks, and all the way up to the application code. With the proper tools, you can record everything your app is doing with very little overhead.
In addition, the GCs and the compiler are pretty much the best in the business, and the next-gen compiler, Graal, is probably the biggest breakthrough in compiler technology of the past decade. Apart from jaw-dropping optimizations, it lets you control machine code generation.
Last but not least, critical parts of the standard library (though not all of it) -- such as the concurrency packages, which contains schedulers and concurrent data structures -- are of quality that is hard to match.
The ecosystem is great, but it has its own limitations. For example, to my knowledge Scala has not been able to implement tail recursion optimization, citing JVM limitations.
Sure, and one day the JVM will get TCO just as it's getting value types (which is perhaps an even bigger current shortcoming), but that is a small price to pay for the ecosystem.
> Sure, and one day the JVM will get TCO just as it's getting value types
You're more optimistic than I am. And honestly proper TCO doesn't seem to be all that important to "regular" java programmers[1], it's just that it's crucial for $ALT_LANGUAGE implementers. (Where ALT_LANGUAGE has a functional flavor.)
[1] I'm guessing that this is the reason that it hasn't been prioritized... but who knows what complexity would rear its ugly head if one were to actually try to implement TCO on the JVM... I'd hazard a guess that it's 'highly non-trivial'.
The JVM is full of large projects that are only relevant to non-Java languages, like the vast bulk of java.lang.invoke, the Graal/Truffle projects etc. They've seemed serious about non-Java languages for a long time now. However/unfortunately, almost all the work has gone into support for dynamically typed languages like Ruby or JavaScript. Given the relative popularities of dynamic vs FP languages that's not surprising. If FP languages that relied on TCO were far more popular it'd probably have been prioritised already.
Tail recursion is fully supported in Scala. The problem lies in more general recursion, i.e. two functions that call each other recursively will grow and eventually blow the stack.
BTW, there is a Scala compiler annotation that helps you check whether a function is tail-recursion optimized.
You're talking about two different "tail call optimizations" here.
Scala supports local tail call optimization for a single function. A lot of FP languages support mutually recursive tail call optimizations, where two functions recursively call each other (common in FP). Scala (and no JVM language to my knowledge) cannot optimize this and so programmers have to resort to workarounds like Trampolines.
In contrast, LLVM IR and .NET CLR support it, allowing language compilers to use it. F# supports it and there's plans for C# to support it. It might be supported in the LLVM Scala target (Scala native) at some point in the future.
This is one of those cases where it doesn't matter that much. World domination is overrated. The JVM's prevalence largely takes care of platform availability. Java interop ensures enough libraries will continue to be available for use. And Jetbrains' internal use of kotlin on a large codebase ensures the language's sustainability. What more is needed?
I would want to see a bigger adoption and companies start using it more often, so I can use it in more projects. I really like using it over other languages.
Every time I write java I think: I would had spent less time writing this in kotlin and the code would be more readable.
Every time I use a non-statically typed language and have a bug because of it I drop a tear thinking that I would never had that bug that took me a couple of days to find in kotlin.
Oh sure it would be nice to see it adopted more widely. I just mean it's not in the vulnerable position of most new(ish) languages. Kotlin is ready for use in any suitable project by anyone who likes it. Though I'm a bit raw with it as yet, I love it for Android. Look forward to seeing the javascript & native possibilities.
Well, it is broadly used by Android developers. For me Kotlin is above scala just because the tooling support (JetBrains the main developers of kotlin), and I find a big difference when writting kotlin and scala. I feel scala more difficult to read, while kotlin is just a pleasure to read code. Moreover you can mix java and kotlin in the same project without issues.
I don't mean to say it will be behind Scala, I just mean to say that it will end up in the same situation as Scala, a language that was meant to be a "better Java" but could never gain enough traction to take off.
When I used Scala I never though it would be better than java, just another alternative. But I think kotlin is better than java. I hope it gains traction but not sure about it.
Kotlin has a much smaller learning curve than Scala. I find it to be much more useful than any other language I've tried out. It has shiny, useful features like some of the more dynamic languages do, but it's close enough to Java that I'm comfortable using it.
Kotlin's design was heavily influenced by Groovy. You can see it in the builder DSLs, the syntax, the fact that Gradle is adding support for Kotlin alongside Gradle, and comments by the Kotlin designers. The big difference of course is that Gradle is dynamically typed by default.
> Gradle is adding support for Kotlin alongside Gradle, and comments by the Kotlin designers. The big difference of course is that Gradle is dynamically typed by default.
You've fallen for the trap of mistaking Gradle to be Apache Groovy, perhaps because those 10-line build scripts for Gradle are the only encounter most programmers have with Groovy. Your comment should read "Gradle is adding support for Kotlin alongside Groovy, and comments by the Kotlin designers. The big difference of course is that Groovy is dynamically typed by default."
It's similar to Groovy, which I've worked with non extensively, but I think it adds a lot more. I've always found development in Groovy to be closer to Ruby or Python, while Kotlin feels more like Java (just better :-)
I find the compiler a "tad" slow, just a tad, I don't know if it's a matter of prioritization or semantics. If the thing was javac-ish, I'd probably make it a daily driver.
What I think it is slower right now are the tools. Sometimes IdeaJ stucks. I guess they will be improving the performance slowly as right now they are other things in the language more important to focus.
Jetbrains uses Kotlin for their own projects, including Intellij Idea. So you can be sure, that its support will be reasonably good, they use it themselves after all.
> I feel kotlin is a bit undervalue. It is a great modern language which can replace java completely.
It doesn't offer a compelling advantage. "Slightly cleaned-up Java with a bit of syntax sugar" is not enough to justify having to make all your tooling (IDEs, profilers, monitoring, code coverage ...) support a new language. And if you are going to make all that effort, why would you not pick a language that offers some genuine killer features in return, like Scala or Ceylon? And it's got a lot of special cases, a lot of stuff in the language that should just be libraries, that I think will make it hard to maintain in the long run (the "CoffeeScript of Java" line is probably fair). If anything it seems overhyped to me.
> "Slightly cleaned-up Java with a bit of syntax sugar"
This is not an accurate description of Kotlin.
Kotlin has many features that make it better than Java. Most importantly, it is null-safe. In addition to that it makes it simple to enforce data-immutability, which is very difficult in Java.
> Kotlin has many features that make it better than Java. Most importantly, it is null-safe. In addition to that it makes it simple to enforce data-immutability, which is very difficult in Java.
Kotlin does have nullability handling yes, but it's a very limited special-case feature - it's a language-level builtin rather than something you can use in your own libraries. E.g. if you want to have an error message in the failure case rather than just null (i.e. some kind of Result type), you can't reuse any of the null-safety functionality (whereas in Scala or Ceylon you can write the same methods to work with either optional/nullable or result-like types).
Data immutability isn't at all difficult in Java. It's tedious (sprinkling "final" everywhere), but not hard.
> it's a language-level builtin rather than something you can use in your own libraries
The only people who still think that a library approach is superior to a compiler approach are Scala users.
I'll clarify this for you: if it's a library construct, it can be ignored. And as a matter of fact, there is nothing in Scala forcing you to use `Option`. You can completely ignore it and enjoy your time diagnosing NullPointerExceptions everywhere.
When a feature is enforced by the compiler, such as Kotlin and Ceylon, you don't get any easy way out: you have to think about null cases or you will not be able to compile your code. Period.
You're conflating two different issues. Yes, Scala allows null and yes, this is unfortunate, though it raises the question of whether there's any better way to do Java interop (you can either assume all Java calls are non-null unless checked, assume all Java calls are nullable and force checking, or trust annotations; all these approaches suck in their own way). It can be mitigated with WartRemover.
But the right way to represent absence - whether you call it null or option or something else - is clearly with a normal type that follows the normal rules of the language, not a special language-builtin type with special language-builtin rules. Some light syntactic sugar for commonly-used types makes sense (like Ceylon's "?"), but what it desugars to should always be something you could write a normal library type for. Indeed if your language doesn't let you implement the constructs you need for this kind of type in a custom type in a library, that should be a red flag that your language isn't expressive enough for general-purpose use.
> (you can either assume all Java calls are non-null unless checked, assume all Java calls are nullable and force checking, or trust annotations; all these approaches suck in their own way)
Agreed, which is why Kotlin has explored all of these options and ending up implementing neither.
> "Slightly cleaned-up Java with a bit of syntax sugar"
And C is a "slightly cleaned-up assemble with a bit of syntax sugar". I think kotlin has a lot of features that Java (even Scala an Ceylon) doesn't have, moreover it forces you to use good patterns when programming (it got a lot of ideas of effective java book).
I am curious why do you say Scala and Ceylon have killer features, what are those features that Kotlin doesn't have?
Personally I have used Scala and I prefer kotlin over it, even Java over Scala.
> And C is a "slightly cleaned-up assemble with a bit of syntax sugar".
Going from machine-specific assembly to crossplatform C was a huge killer feature at the time.
> I am curious why do you say Scala and Ceylon have killer features, what are those features that Kotlin doesn't have?
Higher-kinded types and/or union types. Those are the real game-changers, even if they don't look like it in simple examples. More concretely, the real value proposition for moving from Java to Scala or Ceylon is "replace all your magic annotation/XML-based proxying/bytecode manipulation with ordinary library functions that follow the ordinary rules of the language".
The term "killer app" refers to an app so amazing, people buy your platform just to use that one app. A killer language feature would be a feature so amazing, people use your language just to get that one feature irregardless of the rest.
One property of a killer app is that people tend to know it when they see it. You don't normally need to educate people as to why they want your app, they already know they do.
Kotlin does have a whole bunch of features and particularly DSL features (with more added in 1.1) to allow usage of "ordinary functions" in places where previously you might have used annotations or bytecode generation.
But in practice the market doesn't seem to value these things all that highly, perhaps because most of the time, people are writing ordinary code that doesn't benefit much from them. It's tough to claim something is a killer feature when people aren't saying "We use Ceylon because it has HKTs" (by 'people' here I mean, more than one or two bloggers).
If you look at any discussion of Kotlin then people do tend to identify killer features for them, but they're not normally type system features, they're more like interop or tooling related features. Ceylon and Scala teams recognise the importance of these things too, but the relative prioritisations have been different, so it isn't surprising that the results appeal to different market segments.
> The term "killer app" refers to an app so amazing, people buy your platform just to use that one app. A killer language feature would be a feature so amazing, people use your language just to get that one feature irregardless of the rest.
Yep. That's how I feel about HKT. I'm never going to program in a language without HKT again if I can possibly help it, and I'll put up with a lot of nonsense from Scala (like the IDE situation being a choice between the one that locks up for seconds at a time and the one that puts spurious error highlights on all your code) if the alternative is not having HKT.
> One property of a killer app is that people tend to know it when they see it. You don't normally need to educate people as to why they want your app, they already know they do.
Eh maybe. The quote about "faster horses" comes to mind. What everyone wants is a language that makes it easy to say what you mean and have it come out correct. But it's hard to know what kind of language facilities would help you do that until you've worked with them - and not just done some small examples but written a real line-of-business app while making a real effort to work with the grain of what those features give you.
Programmers don't tend to value new type system features that highly. I don't think it's to do with ignorance. I'm well aware of Haskell's newtype and would like it on the JVM/with Kotlin, as I think it's easier to write correct software when you have that feature. but I'm not going to pick a language based only on that. The incremental benefit just isn't all that large.
Access to a giant number of quality libraries, though, that is in fact a killer feature. I'll use a language just to get access to libraries. Like how people use Scala just because of Spark or Java because of Hadoop or because they want to write a Minecraft mod.
ScalaZ is trivial once you have the concepts, I can and have reimplemented all the parts of it I need (repeatedly in fact). The same goes for Shapeless - it's good to have a standard definition of these things, but there's really not that much to them, they're actually very small libraries. I need HKT because now that I have HKT in my mental toolkit I'll think of solutions to my requirements in terms of them, and it's really painful to have to manually expand out if the language doesn't let me write down the description I have.
And... everything, really. Everything is trivial once you have the concepts. That's a tautology.
Look, I understand the value of higher kinded types and I really enjoy the kind of Haskell code I write when I make use of them. It's abstraction and reusability at its pinnacle. It feels great.
But by calling it a "killer feature", you are showing that you lost track with the real world and you forgot how long it took you to get there, and whether it's really necessary to be productive at your day job.
Everything is driven by real-world, day job productivity. Just yesterday I sketched out how to implement EitherT to a colleague at my day job (which bans ScalaZ) - not as an abstract exercise but because he was writing some code that he could tell ought to be expressible more simply than it was.
Not being permitted to use ScalaZ really doesn't matter - this is not the first job where I've had to reimplement it and I doubt it'll be the last. EitherT is a triviality, it's a couple of lines in any language with HKT. I could write it in my sleep (and not because I'm some super-smart developer; virtually anyone who's used EitherT could). The same goes for everything in ScalaZ really, at least all the useful parts - the things in it are remarkable not for any complex logic they contain but for the lack of any such logic. In many cases once you've conceived of the type signature the implementation requires no further thought at all. (In the Haskell world they even have a tool, djinn, for generating that kind of thing). But not being able to write the thought down would be a real pain - we'd have to write longer code which would cost the client in the short term, and that longer code would obscure the important parts and be less maintainable, which would cost the client more in the long term.
I mean that's the real proof that the killer feature is not ScalaZ itself but the type-system feature - the fact that I'm willing to take a job where ScalaZ is banned, but wouldn't take one in a language without HKT.
I made small research and I see higher-kinded types very similar to generics, what is the main difference?
> union types
You have Multiple Inheritance in kotlin, which does more or less the same.
> the real value proposition for moving from Java to Scala or Ceylon is "replace all your magic annotation/XML-based proxying/bytecode manipulation with ordinary library functions that follow the ordinary rules of the language"
I don't get this. Xml in java code? Ceylon and Scala I think they compile to bytecode too. Sorry, it doesn't make any sense to me the sentence. Can you explain it?
and have a MyType<List> where something() returns List<String> and somethingElse() returns List<Integer>.
> You have Multiple Inheritance in kotlin, which does more or less the same.
Only if you control the classes involved, and most of the time you don't - I can't see any way to create a union where one of the types is from an external library, not even by making them both subtypes of a common interface. (Particularly frustrating since Kotlin supports extension methods, which have all the same complexity for the reader, but as far as I can see you can add a method to a library type but you can't add an interface onto it). (Also Ceylon's native union types are nicer than subtypes).
> I don't get this. Xml in java code? Ceylon and Scala I think they compile to bytecode too.
What I mean is, real-world Java codebases end up full of proxying/bytecode-manipulation/reflection controlled by annotations and/or (in older codebases) XML. E.g. Spring/Guice, Hibernate/JPA, Jersey, Jackson, Quasar... . It's worth saying that this happens for a good reason: Java isn't expressive enough to practically express functionality that people need, and thus they resort to using these techniques instead (the realistic alternatives are callback hell, dropped transactions, copy-pasted code...). But HKT (and related/similar functionality) give you enough expressiveness to replace these things with plain old code.
I think higher-kinded types is one of those things that make me not like Scala. I cannot think about an use case, but there should be few.
> Only if you control the classes involved
You see it like a problem, I see it like a good practice. You should do whatever you want with code that wasn't meant for something else. There were a long discussion in the kotlin forums about this.
> real-world Java codebases end up full of proxying/bytecode-manipulation/reflection controlled by annotations and/or (in older codebases) XML
I see this in Python, Ruby and other languages. Real-world codebases are similar.
It is clear we think different and we are not going to agree, but I liked the conversation and I learnt new things on the way. Thanks
> I cannot think about an use case, but there should be few.
Once you're used to having them in the toolbox you use them all the time.
> You see it like a problem, I see it like a good practice. You should do whatever you want with code that wasn't meant for something else.
Would you say your classes shouldn't have fields that are third-party library types? Having variants that are third-party library types is just the converse.
> I see this in Python, Ruby and other languages.
I can't speak to Ruby but I have Python experience. springpython is seen as a joke. Python decorators are actual Python functions written in normal Python, not hints to some magic framework that does the actual implementation. Metaclasses are problematic but they don't break the rules of the language to anything like the same extent as happens in the Java world.
> And if you are going to make all that effort, why would you not pick a language that offers some genuine killer features in return, like Scala or Ceylon?
Ceylon because it's a ghost town language that no one uses and that only programming language enthusiasts have even heard of. That's a catch 22 but it's the truth.
Scala because it's too different from Java for many Java programmers to be able to jump in and be immediately productive. It solves problems a lot of Java programmers don't even know they have.
The fact that Kotlin isn't that much different from Java is its compelling advantage. And the places it is different, like non-null types, solve problems that almost every Java programmer is going to understand and relate to.
> Ceylon because it's a ghost town language that no one uses and that only programming language enthusiasts have even heard of. That's a catch 22 but it's the truth.
I know :(. It's just very frustrating to have seen Ceylon and Kotlin come out at roughly the same time with roughly the same goals, one better designed than the other, and then watched the other one win.
> Scala because it's too different from Java for many Java programmers to be able to jump in and be immediately productive.
Idiomatic Scala that makes extensive use of native-to-Scala libraries has this property; Scala written in a Java-like style doesn't. I think it's too early to say that Kotlin won't experience the same thing as an idiomatic Kotlin style and native-to-Kotlin libraries emerge.
> It solves problems a lot of Java programmers don't even know they have.
The fact that Kotlin isn't that much different from Java is its compelling advantage. And the places it is different, like non-null types, solve problems that almost every Java programmer is going to understand and relate to.
I think you would have to have a very finely calibrated level of attention to notice null was causing you problems and not notice that exceptions, AOP magic and the like were also causing you problems. I mean I'm sure many Java programmers regard bizarre transactionality bugs ( http://thecodelesscode.com/case/211 is a good example ) as an unfortunate fact of life rather than something to be fixed by better languages - but I expect those same people would also regard null pointer exceptions as an unfortunate fact of life.
> I mean I'm sure many Java programmers regard bizarre transactionality bugs ( http://thecodelesscode.com/case/211 is a good example ) as an unfortunate fact of life rather than something to be fixed by better languages
This is very true but I'll actually admit even I'm not clear how more powerful languages would solve the specific problem you linked. Not saying they can't, just that I don't know how they can.
> but I expect those same people would also regard null pointer exceptions as an unfortunate fact of life.
Not so sure about this one. In my experience it's pretty common for developers to ask "Why can't Java be smarter and realize I never want a NPE and instead of throwing one just automatically make the result of the line it happens on null?"
Obviously that's not the same as asking for non-nullable types but it is asking for the language to solve the NPE problem.
> This is very true but I'll actually admit even I'm not clear how more powerful languages would solve the specific problem you linked. Not saying they can't, just that I don't know how they can.
Well, it's not so much solving it as solving it practically. Even in Java it's obvious what the solution is: have a single method for performing database transactions that opens and closes the transaction so that it's impossible to get the transaction boundaries wrong (the problem the annotations were introduced to solve), and have operations that need to happen inside a transaction represented with a type that can only be used by calling that method (combined with some way of enforcing that you can't "smuggle" the database connection out of that type - or else by separating interface and implementation and ensuring that the module in which your database operations are defined simply doesn't even have access to the database libraries).
The reason people don't do this in Java is that you lose compositionality. The idea exists up to a point - it's sometimes called the "command pattern" - but if you have a bunch of functions that return commands then you need to be able to combine them to happen in a single command (so that you can run them all in the same transaction), and if you don't have that then you lose the ability to split up your code into small reusable functions. You can write functions for composing commandey functions, but you have to write them all yourself for your specific command which ends up being pretty much the same problem. To be able to have a library of functions for dealing with commands in a generic way you have to be working in a language with HKT. Ideally you also want syntax sugar for composition (in Scala, for/yield) so that you can compose command-ey functions more-or-less like regular functions.
> In my experience it's pretty common for developers to ask "Why can't Java be smarter and realize I never want a NPE and instead of throwing one just automatically make the result of the line it happens on null?"
> Obviously that's not the same as asking for non-nullable types but it is asking for the language to solve the NPE problem.
Up to a point, but I suspect they'd ask the same about exceptions. And I don't think they'll find Kotlin satisfactory in that regard either - IME this line of "magically fix it" thinking doesn't actually work, because the appropriate action takes some actual business-dependent logic to determine.
While Kotlin itself is a nice modern swift-like language, it'll never get the same type of adoption unless Google makes it a priority.
I'm a lead Android developer and I've inherited a Kotlin codebase mixed with Java, and here's why I refuse to create any new classes in Kotlin:
1). Compile-time is slow. I know there are plenty of work-arounds but I don't want to modify the build-properties to the point where it's hard to replicate when onboarding new engineers. The closer to the default-project settings, the better and the less resistance. Android dev itself is a very fragile framework to begin with.
2). Abuse with nullable types. I've been a lead iOS engineer too and this is what I have observed as well with Swift. I can't even count the amount of Crashlytic reports that have been caused by a model not binding properly.
3). It really doesn't save that much time at the end of the day. A language is a language is a language.
4). Community/docs does not have as much reach as Java in terms of docs.
This speaks more to the previous developer than the language itself, but this has been the most unstable code-base I've ever worked with.
I specifically avoid web-development for the bandwagoning hype when the shiniest new piece of tech comes out. While I think it's great that Jetbrains is trying to make a competitive language to Java, I think there are too many forces working against them.
Java's old, boring and predictable, but that makes it a great language to a build a stable app with.
What kind of abuse? Too much or too little nullability?
I mean, in Java anything can be null unless it's a primitive type, so that should give you even more problems. Unless it's some sort of mapping of nullable values to non-nullable types that's giving you these crashes?
Too many engineers get caught up with the minor details of the syntax of a language and ignore the business implications of using an untested technology.
My job as a lead is to help scale my team, properly architect the application as well as reducing any risk / uncertainty while delivering new features to the platform.
The syntax doesn't save that much time in my personal experience. The actual amount of words that's typed might be less.. it can be cleaner than Java but if my team is spending a higher amount of time debugging Kotlin issues relative to working with the Java codebase then we've got a problem.
---
> That's a... surprisingly uninformed statement from a "lead" developer.
That's a... surprisingly snarky / unhelpful remark with no counter to my statement.
Kotlin has been useful to me and easy to learn. It dovetails so well with exisiting java libraries that no Kotlin revolution (rewrite everything) is necessary. The most notable frameworks are in android land (Anvil, Bansa -- like react, redux). But on the backend, you can use stardard stuff. That's why Kotlin has been well accepted but not made a huge splash.
"onEach" looks helpful. I actually just added such a function to my own Go extension project, although I named it "tee". The benefit is that when you have a long chain of map -> filter -> reduce, you can insert a tee as a sort of "porthole" into the current state at any location in the chain. Very handy for things like debugging and logging.
It is not like java peek at all (or I am missing what peek do your refer to).
Peek is to get the reference of the first element. OnEach makes a lazy operation for every element on the sequence. I would say that onEach is more like map but lazy.
> On iterables it behaves like forEach but also returns the iterable instance further. And on sequences it returns a wrapping sequence, which applies the given action lazily as the elements are being iterated.
like forEach and also returns the iterable instance or like map, it is the same.
For me the key thing is that onEach applies lazily for sequences.
Map builds a new collection based on the function you provide it. At the end of a map call you end up with a potentially transformed collection instance.
You should consider change your tone when you talk to people. It is quite rude.
It is not a map and it is not a forEach, that is why they created it.
> At the end of a map call you end up with a potentially transformed collection instance
The difference between onEach and map is that map returns a new collection that can have different type of elements. But onEach can modify the internal state of the objects when applied. Also onEach is lazy and map is not lazy in kotlin (as far as I know).
Why did I make the comparison with map and not with forEach? Because forEach is basically a translation of a for and map is a functional function and onEach it is also a functional function. You can agree or disagree with my way of trying to explain things, but being rude in your comments saying you are not right (when I know) and them providing another solution that you also know it isn't right, feels like a troll comment.
Along with swift, they should be the general purpose programming languages in the near future.