top | item 41384852

(no title)

Blot2882 | 1 year ago

I'm not sure how someone could see Kotlin as more expressive than Python, unless I am misinterpreting what expressive means. Python has a good language features and helpful abstractions like list comprehensions.

What makes Kotlin more expressive? I understand it has some functional features but I've never seen anything dramatically flexible.

discuss

order

lolinder|1 year ago

Kotlin's standard library has ruined me for other languages, especially its collections library. The consistency and comprehensiveness of its approach to collections is unmatched in any language I've tried, including all the big name functional languages. It's hard to get across what's so great about the library in writing because it's not just one standard library function, it's how they all interact with each other and how they interact with the language design—you really just have to try it to understand. The net result is that transforming data from one shape to another flows effortlessly, with the dot operator seamlessly connecting a stream of transformations. The fact that it's the dot operator also means that you get really great autocomplete to help you on your way.

Python, meanwhile, has always felt pretty awkward to me when it comes to data transformations. Comprehensions are okay, but they feel like they are special casing what should be a bunch of standardized helper functions operating on lambdas, as a sort of ugly workaround to the fact that Python refuses to implement proper lambdas. And when you can't use a comprehension, you're stuck with a pretty awkward collection of helper methods that are hard to find and use correctly and which are severely handicapped in expressivity by the lack of a proper lambda.

yuye|1 year ago

Couldn't agree more if I tried.

Scope functions are also great.

And the syntactic sugar where `foo({ a -> a })` and `foo { a -> b }` are the same makes code so much more readable.

I've done Python for a project at a previous job for a few months and it made me realize just how awful Python is, especially because you can't chain functions on collections as easily as you can in Kotlin. I also made me realize that I don't like dynamically typed languages.

kaba0|1 year ago

> Kotlin's standard library has ruined me for other languages, especially its collections library

Scala has it beaten by a long shot, in my opinion, and is hands down the best of any language around collections.

wavemode|1 year ago

> Python refuses to implement proper lambdas

Python has lambdas. What do you mean by "proper" lambdas?

Larrikin|1 year ago

As someone who uses Kotlin for work and Python for side projects (and loved Python years ago in college), Python's list comprehension feature is one of the things I hate the most about the language now.

As a simple example using only two collection functions I find it much easier to read

  val hundredOrLessEvenSeconds = (1..1000)
      .toList()
      .filter { it <= 100 }
      .filter { it % 2 == 0 }
      .map { it.seconds }
than

  hundred_or_less_even_seconds = [timedelta(seconds=it) for it in range(1, 1001) if it <= 100 and it % 2 == 0]
But there are tons of helper functions in the collections library to express that in a variety of different ways. But not in a gross code golf way, with clearly named functions

Theres just so much built in https://kotlinlang.org/docs/collections-overview.html

Having lambdas built into the language from the start leads to a ton of expressibility I miss when using python

wk_end|1 year ago

Not that I especially want to defend Python, but can you elaborate a bit on why you find that chain easier to read? The Python version is straightforward enough - if it's just the absence of newlines you can write

  hundred_or_less_even_seconds = [
    timedelta(seconds=it)
    for it in range(1, 1001)
    if it <= 100 and it % 2 == 0
  ]
Also, I don't know Kotlin well enough, but is what you wrote going to be efficient? The Python version iterates once and creates one list (and you can actually turn it into a generator and make zero lists just by swapping the square brackets for parens); to my untrained eye, it looks like the Kotlin version is going to do more iteration and make four separate lists, three of which are just garbage to be thrown away immediately. Here that probably doesn't matter, but in other cases it might be a big problem; is there an easy/idiomatic way to avoid that?

wenc|1 year ago

Python's list comprehensions are close to set notation in math. Here's Python:

    [2*x for x in range(n + 1) if x <= 100]
Here's set notation:

    {2*x | x in 0..n, x <= 100}
So it reads pretty easily for those of us used to set notation. Haskell is even more similar to set notation:

    [2*x | x <- [0..n], x <= 100]

hughesjj|1 year ago

Gotta be real, I don't see any difference in readability (assuming it was formatted the same way, and honestly I'd prefer a different variable name than 'it' in both cases but I get that would require more boiler plate in kotlin and 'it' is a common invention).

The main difference imo is that kotlin uses more "syntax" while python uses more "English" to express the same thing. Also the half-open interval for range but that's an arbitrary decision that benefits some cases more than others (although my preference is the closed interval)

yuye|1 year ago

You don't even need to create a range! You can just use:

    List(1000) { i -> i+1 }
Which creates a list of 1 to 1000

sampo|1 year ago

    import datetime
    import pandas as pd

    hundred_or_less_even_seconds = (
        pd.Series(range(1, 1000))
        .loc[lambda x: x <= 100]
        .loc[lambda x: x % 2 == 0]
        .map(lambda x: datetime.timedelta(seconds=x))
        .to_list()
    )

FridgeSeal|1 year ago

Pythons list comprehensions are sort of fun, but occupy that space because the language designers throttled the alternatives pretty hard.

I used to write a lot of Python, I now write a lot of Rust, and the Rust iterator chains feel inordinately more powerful, and list comprehensions feel semantically backwards to me now: what you’re doing, what you’re doing it to, and whether to do it conditionally are all out of order.

To me, Python feels “expressive” because you can “do stuff to make it work” not because of any inherent design that lets you properly express what you’re trying to do.

rbehrends|1 year ago

As somebody who uses and likes both Kotlin and Python (and quite a few other languages), I'd be cautious with using a subjective term such as "more expressive", too, but I can possibly shed some light on where such feelings come from.

Personally, I see Kotlin as the closest thing to a statically typed Smalltalk that we have among major languages, and that's a major draw.

A key part here is that Kotlin closures are fully-featured equivalents of Smalltalk blocks (up to and including even non-local returns [1]), whereas in many other languages that falls short. Java does not allow mutation of local variables and Python restricts lambdas to normal expressions.

I find code whose behavior can be parameterized by code to be an essential feature of modern-day programming and this should be as frictionless as possible.

This is also a situation where syntax matters, and while it isn't quite as nice as Smalltalk, Kotlin's syntax (esp. with trailing closures) make such code as readable as possible in a brace-style language with minimal additional syntactic noise.

In a similar vein, the functionality of Smalltalk's cascades is offered through scope functions [2], especially `.run {}`.

But ultimately, fully-featured closures (and the fact that they are widely used in the standard library) power a lot of the things that people seem to like about Kotlin.

That does not mean that there aren't downsides. The limitations of running on the JVM are one (e.g. while Kotlin has workarounds for the JVM's type erasure, they're still workarounds), and then Gradle is arguably Kotlin's weakest point (which apparently even JetBrains are seeing, given their investment in Amper).

That said, personally I'd say Kotlin's static typing and performance would be the primary reasons for me to reach for Kotlin over Python, not necessarily expressiveness. Type annotations in Python + mypy etc. just aren't the same experience, and writing performance-sensitive code in Python can be very tricky/hacky when you can't delegate the hot paths to numpy or other existing C/C++/Rust libraries.

Conversely, Python often has a leg up when it comes to fast prototyping and scripting, even with Kotlin Worksheets in IntelliJ IDEA and with kscript.

[1] Which, to be clear, are a nice-to-have thing, not essential, but still impressive that even that was covered, when previously Ruby was the only major language I know of that did it.

[2] https://kotlinlang.org/docs/scope-functions.html