
Problems with Kotlin - andreygrehov
https://kukuruku.co/post/why-kotlin-sucks/
======
ghostc0der
"Actually, I wouldn’t care about for if there was an alternative. But there
isn’t one."

Learn the collections library.
[https://kotlinlang.org/docs/reference/collections.html](https://kotlinlang.org/docs/reference/collections.html)
All loops can be written in terms of them. Also because of inlining they have
have the same runtime costs as hand written for loops.

"Smart cast to ‘Int’ is impossible, because ‘value’ is a mutable property that
could have been changed by this time"

Smart casts only work on immutable values because of concurrency. If the
variable hast to be mutable use ?.let { ... } instead of smart casts.

What's wrong with two exclamation points? If you're using it you are probably
doing something wrong anyway.

When getting a type from Java that hasn't been annotated as @NonNull or
@Nullable it is regarded a platform type. This means it's programmers
responsibility to check if it can be null. Same as in Java or any other
language that doesn't have nullable types.

Assignment is not an expression. We've written 20K of production Kotlin code
without this ever being a useful convention. Assignment being an expresssion
is layover from the C family of languages. If you really want C's syntax and
semantics, go write C.

The ?: operator is great when chaining a bunch of operations all of which
could return a null which we want to convert to a default. Here is an example:
claimData?.claimTimeMinutes?.toLong() ?: 5L

Generics in Kotlin have the same issues as Java because of type erasure. It
does offer a few improvements with the use of reified type variables.

Lastly, if you want to have descriptive structures use data classes.

This guy just wants to program in C. If it's not C it's crap according to the
article.

~~~
mmebane
> Assignment is not an expression. We've written 20K of production Kotlin code
> without this ever being a useful convention.

Out of curiosity, what is the idiomatic way of writing an input loop? The
C/Java way would be something like

    
    
        int bytesRead = 0;
        while ((bytesRead = in.read(buf)) != -1) { // ...
    

> The ?: operator is great when chaining a bunch of operations all of which
> could return a null which we want to convert to a default. Here is an
> example: claimData?.claimTimeMinutes?.toLong() ?: 5L

I think the author is referring to the ternary operator, not the elvis
operator.

~~~
nostrademons
Most likely:

    
    
      in.buffered.readText()
    

The Kotlin stdlib has a rich set of extension methods for reading in whole
files of various common formats at once. readText() reads it all into memory
at once. readLines() reads it into a list of Lines. forEachLine{} runs a
closure on each line. useLines reads it into a sequence (a lazily-evaluated
collection) and then passes that into a closure. buffered converts it to a
BufferedReader, basically wrapping it in your buffering loop. inputStream
converts it to an InputStream, reader to a Reader, and most common Java
protocol libraries take one of those two, so if you need something more
complicated you just pass that in.

I've yet to write an input loop in Kotlin.

------
Nycto
I'm a huge fan of Kotlin. I think the author just doesn't understand the niche
it hits.

My team has a significant investment in the JVM. I despise working in Java
because of how heavy it is to write. I like Scala, but the team I'm on finds
it too complicated. Clojure is out because nobody on the team wants to write
lisp. And Groovy doesn't have types. We looked at Ceylon, too, but at the time
we hit a lot of compiler issues (if I remember correctly).

So where does that leave us? There are likely other languages we could choose
that target the JVM, but the pragmatist in me says I don't want to stray too
far off the beaten path for this.

Is Kotlin perfect? No. But is it a better developer experience than Java? Oh
hell yes.

~~~
lmm
What did you struggle with in Scala? Anything you could write in Kotlin you
can write in Scala with the same structure. Scala has some extra constructs
that can save you a lot of code a lot of the time, but you don't have to use
them if you don't want to. There are horribly incomprehensible libraries
available in Scala and there aren't any for Kotlin yet, but I think that's
just a function of the fact that Kotlin's so much less mature all-round, and
again you don't have to use them.

~~~
veli_joza
The "just don't use those parts of language" argument was also used a lot for
C++. I just don't buy it.

You are not in sole control of your code base. You share it with your
colleagues who are on different skill levels. You are drawn into community
gathered around the language and you need to use, debug, and sometimes
contribute to other people's code. Just fencing off some common language
features isn't going to cut it. It's better to select tools that are well
suited to problem at hand, at right level of abstraction and of manageable
complexity to your team. Even if that means less features and more ground
work.

~~~
pharrington
Don't confuse the argument of "you don't have to use language features you
don't understand" with "certain language features are heavily restricted, if
not verboten, in many organizations'/projects' style guidelines." Certainly,
many programmers don't understand variance, type classes, and other language
tools Scala either has direct support for or is powerful enough to implement
and use in a simple and clean fashion. Those advanced tools are often used to
reject errors at compile time rather than run time and implement certain types
of optimizations without sacrificing safety, code maintainability, or
legibility.

Again, using Scala's advanced features isn't akin to something like using raw
pointers in C++. I find Scala's collection library a good example of that -
programmers of all levels can use Scala collections without understanding all
the type-level tech they're implemented with.

~~~
vbezhenar
> I find Scala's collection library a good example of that - programmers of
> all levels can use Scala collections without understanding all the type-
> level tech they're implemented with.

That was my reason to dislike Scala. It doesn't work for me. I must be able to
dig into any library code I use. And when I tried to dig into Scala
collections library, I ran away screaming in horror. When I tried to implement
my own collection based on linked list, I wasn't able to do it. I was able to
learn Java collections easily, they are really easy to use and understand. You
just open Collection.java, List.java, ArrayList.java and read it, it's easy.
It might be hard for something like ConcurrentSkipList, but this structure is
hard, it's okay. But when I tried to read Scala's collection in the same way,
I drown in traits.

May be there are people who can use libraries purely from interface and
documentation perspective. I'm implementation guy, when I have a question,
first thing I'm doing is investigating implementation code. And if
implementation details are buried below kilometers of abstraction, I don't
like it.

~~~
lmm
The Scala collections library has a fair bit of second-system effect and plain
bad design. It's being rewritten with simplification as an explicit goal (even
at the cost of sacrificing some expressiveness) for the next major version of
Scala. In the meantime there are a couple of alternative libraries, and
fundamentally the standard one does work. (If you need to implement a custom
collection the recommendation is to only implement an interface - or maybe
even just a suitable typeclass - and not try and reuse any implementation
traits/base classes from the standard library).

Which is to say, I don't blame you, but FWIW collections are a known-bad part
of the language and exemplify a lot of what the community wants to move away
from. I find Scala is great for being able to read the implementation of
things, particularly in terms of how much the frameworks tend to be written in
plain old Scala code rather than magic annotations or what have you (e.g. in
Spray/akka-http, all the directives you use to define your web routes are just
ordinary Scala functions and you can click through and read their
definitions).

------
norswap
The post hits a lot of real pain point when working with Kotlin.

In particular, nullable types seem like a good idea (I thought so as well) but
in practice are a real PITA. That's most acute when defining fields, where
non-nullable fields have to be initialized directly.

JetBrains themselves realized it was painful, and so we have `lateinit` to
define mutable non-nullable fields that can be initialized later. But
sometimes it really is nice to be able to check if a field has already been
initialized, which you can't do here.

I must now have spent an order of magnitude time dealing with the
initialization of non-nullable fields than I ever did tracking null pointer
exceptions.

That being said, Kotlin is still a net improvement over coding in Java. In
fact, if you're going for a large codebases, I think it's one of the most
tractable languages out there (C# is a strong contender as well).

~~~
snuxoll
> In particular, nullable types seem like a good idea (I thought so as well)
> but in practice are a real PITA. That's most acute when defining fields,
> where non-nullable fields have to be initialized directly. > JetBrains
> themselves realized it was painful, and so we have `lateinit` to define
> mutable non-nullable fields that can be initialized later. But sometimes it
> really is nice to be able to check if a field has already been initialized,
> which you can't do here.

I'm curious, where have you found the need for lateinit? Forcing
initialization of non-nullable types has always seemed like a great idea to
me, and learning to deal with it in Kotlin has made picking up Rust a lot
easier.

~~~
dimillian
JSON and reflection, you know you gonna get a value once you'll have
instantiated your object from a JSON description. So my var are lateninit
because I don't need a ? or !!

~~~
snuxoll
Initialize them with default values, then? Or if you're using Jackson there is
a module from FasterXML that provides support for Kotlin data classes.

lateinit is a crutch to get things working, not something you want to use
long-term.

~~~
afastow
Lateinit is good for what it is designed for which is allowing for fields that
are _always_ going to be initialized before use but after construction,
normally by a library. I wouldn't describe it as a crutch in that case.

It'd be ideal if libraries were better about using constructor injection when
possible, but I think there are some valid scenarios where circular
dependencies make it impossible to use only constructor injection.

~~~
snuxoll
> It'd be ideal if libraries were better about using constructor injection
> when possible, but I think there are some valid scenarios where circular
> dependencies make it impossible to use only constructor injection.

Thankfully it is rare to require circular dependencies, but this is probably
the one use case where lateinit is certainly warranted.

------
simias
I've never used Kotlin (and I haven't touched Java in more than a decade) so I
can't really comment on the usability issues of the language. That being said
I think he completely misses the point of the nullable types and he's fighting
them because he's treating them like "void * " instead of trying to understand
how to work with them.

In particular, to his:

> Where does this absolutely crazy confidence of a compiler that each
> character of my program is an element of multithread concurrency come from?

I'd reply: why would the compiler have this absolutely crazy confidence that a
particular character of your program _isn 't_ an element of a multithread
concurrency? Why do you want your compiler to make assumptions about your code
if it's not able to enforce them?

I don't know what's the right way to write what he means in Kotlin but in Rust
it'd be something like:

    
    
        match (value) {
            Some(v) => v,
            None => 0
        }
    

Or alternatively:

    
    
       value.unwrap_or(0)
    

Which are both safe and, in my opinion, clearer than the proposed code in TFA.
I would assume that Kotlin has a similar syntax for that use case?

That being said I can imagine that having to interface with Java (which
doesn't share the same "mindset") might be frustrating. It helps when all the
language and its libraries are designed from the ground up around a certain
paradigm.

~~~
algesten
I agree. I used to argue like the author, that null is a thing in computing
and I just had to deal with it.

But after spending some time in Rust and Swift, I learnt a whole new way of
thinking about it. The killer combination is:

no null + immutable

I've taken this to javascript, and it is so much better. Just don't accept
null values anywhere in the model code, and suddenly writing view code is
super easy.

No more endless if-cases or ternary to deal with nulls.

~~~
gagege
Yes. I usually refer to them as "optional" values, rather than "nullable"
values. Something should only be null if it is truly optional to the class,
view or whatever, which is a pretty rare thing. If a class requires a certain
value to be able to do it's work, and that value is missing (null), why was
the class even instantiated? That should be a big no-no.

------
mathw
Honestly I started out thinking this article was satirical, and I'm not at all
convinced it's not now, but it's a bit difficult to tell around the author's
probably-non-native grasp of English.

Everyone else seems to be treating it like it's serious though. Maybe I'm just
too infused with the joy of Rust, Haskell and other such languages to think
anything slightly hysterical-sounding about the utility of non-nullable types
and the possibility of mutation by other threads can possibly be anything
other than parody.

------
jorgemf
> This article is based on Your Language Sucks in the form of half a joke.

First I though the article was being ironic, I end up understanding by
thinking it is a completely a joke, not half a joke. Otherwise I do not
understand:

\- why the author compares '?' with '?:' as they are completely different
things

\- complains about automatic casting of class variables without understanding
that the languages have threads ( "thread intersections occur on a very small
size of the source code, but due to compiler’s repressive care about this
feature" -> it is much better to crash your program randomly in production
than a compiler error, ouh yeah!)

\- complains kotlin has a useless for that only saves some lines of code (like
few lines of codes repeated for every for you write in the code, which it is a
lot of code)

\- complains about the alias without understanding generics

\- complains about poor generics without understanding generics

\- etc

100% I wont hire him as a engineer

------
realharo
The part about maps is wrong, you can write them like

    
    
        val myMap = mapOf(
            "A" to 10,
            "B" to 20
        )
    

etc.

Also, regarding that final sentence about matrices, that sounds like a perfect
use case for type aliases.

------
amyjess
What convinced me that Kotlin wasn't for me was Andrey Breslav's reasoning why
he insisted on sticking to Scala's confusing "Unit" terminology instead of
terminology that actually makes sense [0].

> Why we don't call it "Void": because the word "void" means "nothing", and
> there's another type, Nothing, that means just "no value at all", i.e. the
> computation did not complete normally (looped forever or threw an
> exception). We could not afford the clash of meanings.

And then he doubles down on it in the comments:

> "Unit" just stands for "something that has only one value", it's a
> traditional name, comes from functional languages. I agree that this name is
> not very intuitive, but we failed to invent a better name.

He managed to convince me that Kotlin's highest priority was pointless
academic nitpicking, and that's not what I'm looking for in a language. What I
wanted was a solid JVM language that avoids all the unnecessary boilerplate of
Java without diving headfirst into a morass of functional programming like
Scala. I want something that's 100% practicality and straightforwardness, not
something that thinks trying to emulate higher math is something to aspire to.
Well, I guess there's still Jython, even if it is stuck on an ancient version
of Python... (edit: oh, and Groovy... forgot about it because most people just
use it for Gradle scripting)

[0] [https://stackoverflow.com/questions/22654932/what-is-the-
pur...](https://stackoverflow.com/questions/22654932/what-is-the-purpose-of-
unit-returning-in-functions)

~~~
vorg
> Groovy... forgot about it because most people just use it for Gradle
> scripting

You can use Kotlin for Gradle scripting as well since Gradle 3.0 released
about 6 months ago. Given that Gradleware also said they're switching their
preferred language for Gradle addons to Kotlin from that version onwards, I'm
guessing the same will happen for build scripts some day.

------
relics443
I'm not sure how "tongue in cheek" this article was supposed to be, but most
of his issues with the problem can be solved by buying into the language.

For:

Not sure what he's upset about, but there are many options in the standard
library. I almost never use the language construct for it, and I'm very happy
with it.

Nullable:

I never expected nullable to completely save me from all issues. It has the
same function as the @Nullable and @NotNull annotations (and all the other
variants). It gives you a simpler way to reason about nullability, and forces
you to respond to it; you can't just ignore it.

Smart cast on mutable

I get that this sucks, but they can't show it to happen. Yes, the chances are
small, but there could be concurrency issues. They have to account for that,
and can't tell if your code is multi threaded or not.

Most of the time his issue can be solved with scoping, using ?.let or ?.apply

Java Nullability

What do you want from them? They have no ability whatsoever to control this.
Either get annotations in the Java code if you can modify it (which is a good
idea anyways), or wrap it and provide nullability information.

Assignment is not an expression

He got it. It's too protect against if(v=v). I know he makes a joke about
automatic type casting, but if you're not assigning the result to anything,
the logic in the if will still fail.

Elvis operator

I assume they removed Javas ternary operator to not get confused with the
Elvis operator. ¯\\_(ツ)_/¯ I kind of agree with him here unless I'm missing
something

Automatic type casting

Frustrating, but safe

Type alias

I'm fine with it for simple cases, didn't want to parse his problem.

Generics

I hear his gripe, but at the end of the day Kotlin generics are Java generics.
If there are some potential bugs in the compiler, report them and move on.

Structure syntax

I assume he means list and map literals. I agree it would be nice. Not sure
why they didn't include it.

~~~
lmm
> What do you want from them? They have no ability whatsoever to control this.
> Either get annotations in the Java code if you can modify it (which is a
> good idea anyways), or wrap it and provide nullability information.

What I want is consistency. In Scala optional is always safe and null is never
safe, and that's true whether you're calling a Scala method or a Java method
(even the most perverse Java libraries don't declare themselves as returning
Optional<String> and then return null). In Kotlin null is safe some of the
time and not safe other times, e.g. if you're passing it to a method it might
be fine or might not.

~~~
Nycto
I don't see a huge difference between Scala's Options and Kotlin's null
safety. In Scala, you can still do this:

    
    
        val x: Option[Int] = null

~~~
lmm
In theory you can. But you'd know to immediately fail that line in code review
(or better still, enforce it at build time via wartremover). Whereas in Kotlin

    
    
        someMethod(null)
    

might be perfectly legitimate or might not, but you can't tell without knowing
the details of someMethod (whether it's a Java method or not).

~~~
afastow
Maybe I'm missing something but how is that different from Scala or Java?

That will fail at compile time in Kotlin if the method is written in Kotlin
and has a non-nullable parameter. Even if it's Java I think it will fail at
compile time if the Java parameter is annotated with @NotNull.

If it is a Java method and not annotated with @NotNull then of course it will
be allowed at compile time because how could it possibly not be allowed? What
are you saying is preferable in that case?

~~~
lmm
The trouble is in idiomatic Kotlin you have lines like that, because when you
want to represent absence you use nullable parameters. So you can't assume a
line like that is wrong. But you can't assume it's correct just because it
compiled either, because as you say it might be an unannotated Java method.

In idiomatic Scala you would never have a line like that (because you
represent absence with optionals rather than null). So you can insta-fail any
line like that in code review (or give very careful review in the rare case
that it's calling a Java method that accepts a nullable parameter, but good
modern Java libraries are moving away from those, so that case should go
away).

~~~
hota_mazi
The main difference is that Kotlin can do both: nullable types or `Option`
(and you'd never use `Option` unless you are dealing with it coming from Java,
obviously).

Scala can only do `Option` since it doesn't have built in support for nullable
types.

I fail to see how your point shows any superiority from Scala here, it's the
other way around.

At the end of the day, both languages have nullability support but since it's
optional in Scala (because library based), Kotlin's approach is superior in
that it requires developers to deal with nullability, while Scala developers
can ignore it any time they want.

~~~
lmm
Nullable types are worse than Option in every way that matters (yes they save
a few bytes of memory occasionally, but who the hell cares, if you care about
shaving 8 bytes off an object you won't be using the JVM in the first place.
It's certainly not worth the cost of working with a weird, second-class type
that you can't abstract over like other types). Why do you want an extra way
of representing the same thing with more special cases?

> Kotlin's approach is superior in that it requires developers to deal with
> nullability

But it doesn't force them to deal with nullability _when interacting with
Java_ which is the only case where it matters.

Scala calling Scala: you never use null, you never hit a problem with null.

Scala calling Java: you have to manually check return values for older
libraries but at least passing in null can't happen.

Kotlin calling Kotlin: you use null a lot, you never hit a problem with null.

Kotlin calling Java: you have to manually check return values for older
libraries _and_ won't notice where you're passing in null because that's a
normal, safe thing to do when calling Kotlin.

~~~
nostrademons
I think there's some misunderstanding about what goes on with an Option<T>
type in the compiler. In a sane implementation of Option<T>, there's no space
premium for using it over T. The compiler compiles Some<T> to a pointer to T,
and it compiles None to null. Swift, Rust, and Haskell all do this; I don't
know Scala that well, but I'd imagine it would too unless there's some edge
case in Scala<->Java interop.

Kotlin's nullable types and Option _are exactly the same thing_ , except with
some implicit conversions and smart casts available (marked by the IDE). Using
Kotlin & Rust syntax, I make the following mental equivalencies:

    
    
      T? <==> Option<T>
      maybeNull!! <==> maybeNull.unwrap()
      maybeNull ?: default <==> maybeNull.unwrap_or(default)
      maybeNull == null <==> maybeNull.isNone()
      maybeNull != null <==> maybeNull.isSome()
      maybeNull?.method() <==> maybeNull.map(|v| v.method())
      maybeNull?.method() ?: default <==> maybeNull.map_or(|v| v.method(), default)
    

The comparison is even more apparent if you're used to Swift, which has a
separate Optional type but the same syntactic sugar as Kotlin for manipulating
it.

The two ways that Kotlin nullable types differ from Options in other languages
is that you have smart casts (if the compiler can prove that the value is
never null, you can use it as a normal variable without explicitly
unwrapping), and you have automatic coercions from platform types.

Also, I almost never use null in idiomatic Kotlin programming.

~~~
interestingemu
I think this comment shows a very fundamental lack of understanding how
different languages handle errors.

In Java (and Kotlin) -- ignoring the topic of exceptions as an alternative --
errors like "missing value" are communicated with null.

So in Java you first have an error handling problem, you deal with it by
returning null ... now you have a null handling problem!

Kotlin tries to put some band-aid around nulls by making them more typed than
in Java.

In Scala, errors are handled with bog-standard library types like Option,
Either, Try, Validation, not some special language built-in. These types are
not facilities to handle null (shown by the fact that all these types happily
accept null as a valid value), they are facilities to handle errors.

They handle errors better than Java or Kotlin, because these types allow
developers to choose the appropriate type for a specific error case and retain
the structure of a computation. To expand on the second point: Nullable types
cannot be nested, Scala's types can and regularly are.

This allows Scala to compose operations while carrying errors up to the point
where they can be handled easily.

If you have an operation returning an Option[T], and want to run an option on
the value returning an Either[S, T] then simply looking at the resulting value
will tell you if things succeeded or where exactly things went wrong.

    
    
        None               --> First operation did not result in a value
        Some(Left(fail))   --> Second operation failed with cause "fail"
        Some(Right(value)) --> All operations succeeded with result "value"
    

In Java and Kotlin all you would get would be a bare null, with a probability
of people giving up on (typed) null completely and just throwing an
(unchecked) exception instead.

TL;DR: Kotlin tries to put some band-aid around Java's broken approach of
handling errors with null, Scala deals with errors correctly in the first
place.

~~~
nostrademons
Outside of very specific low-level operations like Maps or taking .first() of
an empty list, you don't handle errors with null in either Java or Kotlin. You
handle them with exceptions. You can't ignore the topic of exceptions as an
alternative - that _is_ the idiomatic way to signal an error in Java and
Kotlin. Nobody seriously considers having high-level APIs return "null" on
error; for one, there's no way to differentiate the different things that can
go wrong.

Now, there's an alternative school of thought that's gaining currency in
languages like Rust, Go, and apparently Scala, and is how we used to handle
them in C. That's to return special out-of-band values as part of the result
type. The Either type in these languages (realistically, you wouldn't use an
Option for any high-level API) in these languages makes this really easy, and
sum types in general make pattern-matching on the specific error code &
passing back diagnostic information a lot easier than it was in C.

I don't really want to get into a debate about error-by-value vs. error-by-
exception, because there are good arguments on both sides of the debate and
it's far from a settled question. Personally, if I were starting a new
language today, I'd use return values for "expected" error conditions and some
sort of panic/recover mechanism to indicate that the programmer forgot to
handle a case.

But there's a really strong reason why Kotlin uses exceptions:
interoperability with Java code. It's the same reason that Google bans
exceptions in their C++ code: you can't really change the error handling
mechanism of a large body of existing code, because the existing code's API
all assumes certain language conventions, and if you break those conventions,
you might as well rebuild the ecosystem from scratch.

So sure, if I were starting a language & ecosystem from the ground up, I'd
probably use return values & pattern-matching. But I use Kotlin specifically
because I want a "better Java", and need to integrate with Java libraries that
may return null and will throw exceptions. If I didn't have those constraints,
I'd use Rust instead.

~~~
interestingemu
I have seen plenty of libraries using null to indicate an error. If this
wasn't the case, as you allege, then why do Kotlin devs act like it's such a
big deal? Why add a language feature for something that isn't even considered
an issue instead of e.g. improving how Kotlin handles checked exceptions?

~~~
lmm
One thing I find really frustrating is that Ceylon didn't take advantage of
its union types to represent checked exceptions that way :(

------
taco_emoji
I really don't understand the complaint about `for` loops... is it just that
you can implement the same functionality with a custom-made function? I don't
really get what's wrong with the language having some syntactic sugar baked
in.

EDIT: should mention I don't know Kotlin so maybe there's something obvious
I'm missing...

~~~
nostrademons
I didn't understand his point either (and I know Kotlin pretty well), but
since 1.1 for-loops are basically deprecated in user code and you'd use the
forEach method on Iterables:

    
    
      collection.forEach { variable -> 
        ....
      }

~~~
vbezhenar
Could you elaborate, why they are deprecated, is there any sources? Actually
I'm always wondering which form of "for" I should use and I always using
language "for" because, well, it's part of language. I actually think that
"for" will be enhanced in the future, e.g. including guards, nested loops,
maps, etc, like Scala's version (or Haskell).

------
ChicagoDave
The impedance mismatch with its intended target (mainly Java) is enough to
make Kotlin a complete waste of time.

~~~
kcorbitt
This is a reasonable critique of other JVM-hosted languages I've worked with
(Clojure and JRuby), but the external interface of classes and methods in
Kotlin are completely compatible with Java by design. And in practice, it's
very easy to write mixed Java/Kotlin projects where you don't necessarily know
(or care) whether the class you just imported was written in one or the other
-- it just works how you'd expect. I'd be interested in specific examples
where you found any impedance mismatch at all.

~~~
didibus
Maybe the closer similarity leads to more confusion and mix up.

Clojure works pretty well with Java, but is so different, you'll rarely get
things mixed up between the two.

Just a guess, since I'm not the original commenter.

------
guelo
I'm just getting started with Kotlin so can't comment too deeply on its
problems but here are a couple things that have already annoyed me.

Kotlin is supposed to be less verbose but variable declarations and function
signatures can get annoyingly long.

    
    
      //java
      String x;
      
      //kotlin
      var x : String?
    

Also, the whole fad of all new languages putting the type after the name
doesn't make sense to me.

Where are the ints?

    
    
      Object objectThing;
      Object someOtherObjectThing;
      int thing;
      int someOtherThing;
      String stringThing;
      String someOtherStringThing;
    

Much harder to find the ints in a long list of Kotlin fields:

    
    
      var objectThing:Any?
      var someOtherObjectThing:Any?
      var thing:Int?
      var someOtherThing:Int?
      var stringThing:String?
      var someOtherStringThing:String?

~~~
oblio
I dunno about you, but I usually go looking for variables (names) and rarely
go looking for types. I rarely ask: "where are the ints?". I generally ask:
"where are the invoices/urls/files/accounts/... ?".

~~~
guelo
I came across that annoyance in Android code where there were 30 some View
fields of different types, TextView, ImageView etc. It wasn't my code so I
didn't know what names had been used but I knew that I wanted to find one of
the TextViews.

In Java Android code we normally group the fields by type to make them easier
to find. But maybe we need a different convention for Kotlin.

~~~
Larrikin
For Android UI components specifically I usually just include the type in the
name. The types can get a little long but when you need to have and operate on
userNameTextView userNameTextInputLayout you end up saving time when looking
back

------
SomeCallMeTim
OK, this seems like a major fail on behalf of the Kotlin developer team:

    
    
        var value : Int? = null
    
        fun F() : Int {
          if ( value != null ) return 0
          return value // error
        }
    

Tracing value types through a function is a solved problem. Look at
TypeScript: Almost the exact function above will work flawlessly. [1]

Sure something in a JVM could be changed by another thread. But that would
really be a bug no matter how you slice it. Doing type analysis like this
seems like a minimal requirement for a modern language.

[1] [http://imgur.com/nxdN9vc](http://imgur.com/nxdN9vc) \-- you can see that
TypeScript can identify the remaining type. It works for optional null as well
when strictNullChecks is enabled.

~~~
pdpi
Look at the code carefully. The only way you can reach "return value" is if
`value == null`, so the compiler complains with "Required Int, found Int?",
because it (quite rightly!) can't prove that value is definitely not null

Let's change it to

    
    
        var value : Int? = null
        
        fun F() : Int {
            if ( value == null ) return 0
            return value // error
        }
    

Now the compiler still complains, with a different error:

"Smartcast to Int is impossible because value is a mutable property that could
have been changed by this time". Right you are.

    
    
        val value : Int? = null
        
        fun F() : Int {
            if ( value == null ) return 0
            return value
        }
    

This version compiles fine because `value` is a constant (though I think the
compiler should've complained about dead code. You can never reach `return
value`.)

    
    
        fun F(value : Int? ) : Int {
            if ( value == null ) return 0
            return value
        }
    

This version also works fine.

~~~
SomeCallMeTim
OK, you're right that he wrote the example incorrectly (mine was a copy-and-
paste from his). The point still stands though.

> "Smartcast to Int is impossible because value is a mutable property that
> could have been changed by this time". Right you are.

I disagree. It _cannot_ have been changed by that time, not unless it was
changed in another thread, and it would be really, really nice for a language
to have built-in threading intelligence to prevent that from being necessary
to check. That's what I'm saying. TypeScript is single-threaded, so it can be
certain that another thread hasn't changed it. Go is multithreaded, but except
for genuine globals (which need to be protected by a mutex, but shouldn't be
used for just about anything) you're piping information from one state to
another, which again doesn't have a synchronization problem.

If you have to manually mark a variable as "safe" every time you use it,
you're just going to need to do that constantly for lots of variables. And you
_still_ are stuck getting the thread safety right: The above code isn't safe
if something from another thread can change value. Which I guess is the point
of the exclamation points, but ... somehow I prefer the Rust approach of "Mark
this block of code as unsafe." Not that I've used either language.

The fact that it works correctly as a parameter, though -- that does hit the
80% case, at least.

~~~
pdpi
> If you have to manually mark a variable as "safe" every time you use it,
> you're just going to need to do that constantly for lots of variables. > ...
> > The fact that it works correctly as a parameter, though -- that does hit
> the 80% case, at least.

That's the thing, it's not "80% of the cases". It actually hits just about all
of them. For this whole situation to be a problem, rather than the compiler
preventing bugs, you need all of the following:

    
    
      — You need a `var`, rather than a `val` (constant).
      — The `var` needs to be nullable.
      — The var is either a module global, or a class field.
      — Your code doesn't touch anything multithreaded.
        This includes not using NIO, or having any callbacks at
        all to libraries that might use threading internally.
    

If any of those requirements is missing, the compilation error is either
legitimate, or gone. In my experience, eliminating the multithreaded part
eliminates all the reasonable use cases for Kotlin-as-a-Java-replacement:
Android, web development, desktop applications.

Not all languages need to be good at everything. For my purposes, I welcome a
language that makes working in heavily-multithreaded environments a bit
easier, and I won't begrudge languages targeting other people's use cases
either.

~~~
SomeCallMeTim
Module global variables, I think we can agree, are less than ideal.

But I was thinking of class fields. I don't really want my compiler to hold my
hand with respect to "nullable", if I know for a fact that, by the time the
code gets there, it can't possibly be null.

Think of it this way: It's not a compile error to access an int from multiple
threads, right? It doesn't require that !! syntax if you're just accessing a
mutable class field or variable? So if I test an int for a value and then do
something that assumes the value is still the same, I'm writing something that
could crash just as easily as the null reference -- and array out-of-bounds,
or a flag that says it's OK to do something but that flag changes after I
check it, because I didn't grab a mutex.

So why does it add an error condition if you're accessing a mutable variable
that's available in multiple threads just because it's nullable? Seems like
extra busy work for no clear benefit for what is, as you say, a rather rare
situation.

If we're going to share data across threads, I'd rather the language not
present a false sense of security as a result of the !! operator.

~~~
pdpi
I think you misunderstood me — the rare situation is the compiler complaining
about valid code. In practice, I find null handling in Kotlin to be quite
straightforward, and it simplifies both writing and reading code a fair bit. I
also find that forcing me to opt in to allowing nulls and, therefore,
complicating my code a bit (by correctly handling them in the implementation)
forces me to clean up my designs a bit.

Now, Jetbrains don't claim to solve data races in general, so it's fine to not
solve all of them. But they _do_ claim to provide null safety in general
(modulo java interop), so they _must_ provide null safety in the face of data
races. I do agree that a language that solves data races in general is very,
very valuable (and that's part of the reason why I've invested some time
learning Rust), but solving nulls better than the half-arsed solution present
in java Optional is, IMO, still quite valuable.

Finally, what do you mean by "a false sense of security as a result of the !!
operator"? The !! operator is effectively "I know for a fact this isn't null,
stop bothering me", and, when you read it, it should raise alarm bells, rather
than make you feel safe. I also object to the notion that a language that is a
bit safer is bad because it lulls you into a false sense of security. That's
like saying that GCs are bad because they lull you into a false sense of
security from memory leaks.

------
hota_mazi
> How can we protect ourselves from something that is beyond the language and
> is not controlled by it? There’s no way to do it.

There are plenty of ways to do it. The most popular is probably to capture the
Java nullability at the border when Java values enter Kotlin code. From that
point on, your code is null correct and will never give you an NPE.

> The Smart cast to ‘Int’ is impossible, because ‘value’ is a mutable property
> that could have been changed by this time error is driving me nuts. I want
> to kill someone or break something.

Yeah, lash at the compiler for pointing out your code is incorrect, right?
Easy solution: use a `val` (which should be your default anyway). Another
solution, although less easy: write better code.

------
hota_mazi
You know a language has reached mainstream when it starts getting "sucks"
articles written about it.

------
maxpert
Reading the article I have thought twice and thrice about how to respond.
Problem is every language can't be C/C++; it's like looking at LISP for first
time and just diving into writing a blog ranting about it. Why does + comes
before; hell = should have been assignment operator, why are things immutable
and blah blah blah. It took me some time to develop taste, but all well
engineered languages are tailored towards a mindset or problem-set. I might
say few of points might be right here but language design is really really
difficult and subjective topic. Try building the language yourself fixing
stuff you just ranted about and I can guarantee you people ranting about the
Frankenstein you will make.

------
StefanKarpinski
It's entirely unclear to me whether this is parody or not.

------
jankotek
I think author would have a hearth attack from Scala. It does not even have a
conditional loops :-)

~~~
esarbe
It does. [https://www.scala-
lang.org/files/archive/spec/2.11/06-expres...](https://www.scala-
lang.org/files/archive/spec/2.11/06-expressions.html#while-loop-expressions)

~~~
jankotek
scala does not have a `continue`, `break` etc.. Kotlin allows that...

~~~
esarbe
It does. [http://www.scala-
lang.org/api/current/scala/util/control/Bre...](http://www.scala-
lang.org/api/current/scala/util/control/Breaks.html)

~~~
abiox
This seems like equivocation.

------
plandis
Fix your website on mobile. The width of the ads is larger than the actual
content.

~~~
andreygrehov
Interesting. What phone are you on? Could be because of a flexbox.

~~~
dpkirchner
Nexus 9 tablet here. While in portrait the content takes up what I'd estimate
to be 40% of the horizontal space, with the remainder used for ads and
whitespace. The code samples are basically unreadable (requiring horizontal
scrolling inside the div).

It's not so bad in landscape, however.

------
gmarx
Here is a meta-comment that may seem irrelevant but I truly wonder about this
odd tick of internet writing.

The title should be "Kotlin Sucks" or "Why I think Kotlin Sucks". The article
doesn't say anything about the circumstances that lead to the sucking (e.g.
the main developer suffered a serious brain injury midway through the project)
he just lists and details aspects of it that suck.

This incorrect, misleading use of the word "why" in the titles of internet
articles is so common I must ask, "why?"

~~~
sctb
You've convinced me that "Why" in this title is a form of a clickbait—perhaps
to appeal to our craving for causality—so we've removed it. Thanks!

~~~
gmarx
Wow. You're welcome and thanks! I don't know why it should make me feel good
that a stranger on the internet took action in response to my comment, but it
does

------
ga2arch
[deleted]

