yes, it is, but it removes an unnecessary characte...
# announcements
h
yes, it is, but it removes an unnecessary character, no?
m
0..2 is unambiguous and doesn’t require extra thought, Concision is not a good goal unless it aids readability. The [2..] variation, though… isn’t that
drop(2)
? Actually, would it be
drop(3)
? Another reason to avoid it. Is it 0-based? Is it inclusive or exclusive?
drop(n)
is again unambiguous. Again, more typing, but it’s already there, and doesn’t require parsing. Same reason I’m opposed to introducing the ternary operator rather than just using
if/else
on one line. If you come from Java/Groovy, you have learned the ternary. If you didn’t, think back to the first time you saw it, and had to have it explained to you. And at least in Java,
?
and
:
don’t have any other meaning, whereas in Kotlin, they have other meanings depending on how they appear.
1
h
I wouldn't want the ternary operator in kotlin since
if/else
is already inline And as I alluded to, yes,
foo[2..]
is the same as
foo.drop(3)
but
foo[..3]
is
foo.take(4)
, but I imagine them being the same function, as opposed to two different functions. Does that make sense?
g
meh.. @Mike it's more like an attempt to reason the current situation, than a real argument. Never
drop
or
take
or whatever workaround name will be cleaner than
[..k]
or
[k..]
. Same reason why
arrayOf()
will be always a sad bump in kotlin.
g
So array should have own special syntax to be "cleaner", but nothing for lists, right? But In our project we have probably 50 cases for lists per 1 array. Also what about type of this array, should [1,2,3] be IntArray or Array<Int>? If we add also collections to this proposal we getting KEEP-113 with a ton of problems
drop and take not just "workarounds" it's quite common list operators across many languages, especially functional ones So range vs operator it's more about case (sometimes you think in indexes, than range looks better, sometimes in list count) and habits (if you come from python or Swift it may be more common to use range)
h
I have a hard time understanding the purpose of the existence of both
IntArray
and
Array<Int>
g
One version is generic and Int will be boxed, another is primitive
h
Doesn't
List<Int>
already cover the former properties?
g
But List is not the same as array, array is also JVM type, it cannot be extended, allocated sequentially in memory
Array is much more low level and most of lists are written using arrays (excluding linked ones)
h
Yeah, that's why I figure
Array<T>
only exists because of its existence in the jvm. We could easily get by with only
List<Int>
and
IntArray
, I believe.
g
Of course it all about JVM and because of way how generics are implemeted
h
Either way, for a language that prides itself in being readable and dispelling cryptic nomenclature and syntax, the existence of
IntArray
and
Array<Int>
is certainly a poignant sour spot.
Maybe in 10 years Kotlin Native will phase out KotlinJVM and KotlinJS
g
This language also prides I terop with existing platforms, and this interop one of main reasons why it is so popular
1
h
and Kotlin can finally slough off the baggage of the jvm
g
It will be really sad moment, because it will happen only if JVM will die, or K/N will be impossible to use for MPP
h
Yeah, I fully understand that this language's top priority is interop
g
JVM is not the baggage, this is one of main forces of Kotlin
h
jvm comes with baggage, rather
it isn't wholly baggage by any means
g
Everything come with baggage
For example this solution about array literal
h
the existence of baggage everywhere is not a reason to dismiss it.
g
So, returning to my question after we drop Array<Int> val a = [1,2,3]
h
is that an
IntArray
or a
List<Int>
, yeah?
g
So a is IntArray, List<Int> or maybe MuyableList<Int>?
Solution: let's add new syntax for list literals, like {1,2,3}
h
<1, 2, 3>
g
And now we have another can of worms: what about compatibility with existing code and will compiler can easily parse it
h
eh
yeah, there's always the concern of existing code
mutability of lists is an enormous can of worms all on its own
I think
List<Int>
,
MutableList<Int>
, and
ImmutableList<Int>
could cover all the bases, meaning both
Array<Int>
and
IntArray
could kick the bucket
But I don't know every use case
🤷 1
g
I want to be clear, I'm actually pro-collections literals in general, I just don't see for now good proposal and solution for known problems It's just really hard to do and I wouldn't like to make language more complicated, because we didn't talk also about maps
h
yeah, and i wanna be clear that I'm very sympathetic toward all your arguments and appreciate your views. i don't wanna seem combative.
g
No-no, it's fine 👍 just tried to show that everything is not so easy
But I also think that for some cases we could have literals, for example for
in
operator Like:
Copy code
if (x in [2,5,7])
And also unroll it on compile time
h
that could also just be set notation:
x in {2,5,7}
g
Yes, but good thing about [] is that we already have array literal for annotations
h
righto
couldn't
[]
be used for list literals and
{}
used for collection or set literals? Since we don't have object literals.
i guess the standard is to use them for map literals, but maps are pretty clearly described in kotlin with the
to
infix
g
In theory set is more correct in terms of semantics, but on compile time, if you want to replace it with intrinsic) there is no much difference
There is also proposal for
to
literal
h
to do what?
g
See KEEP-113
To do mapOf(1: a, 2: b) instead of mapOf(1 to a, 2 to b)
h
ah, yeah
to
isn't any clearer than
:
g
Correct, but
to
is not even part of the language or syntax, so it much more simple
h
yeah it's just an infix for a
Pair.invoke()
g
There are also ideas about constructor literals, to omit class name if type of object is inferred
h
one of the other tops of my wish list, semi-related, is overloadable
as
operator, but iirc that's a feature in a few languages and can make code vague in reading
g
To override cast?
h
yeah
you can do something similar atm with contracts, i believe
would also be nice to have javascript's ability to pass named functions to parameters of lambda type, e.g.
Copy code
fun bar(baz: (Int) -> Any) {
   // stuff
}
fun foo(foz: Int): Any {
  // stuff
}

val bafo = bar(foo)
as opposed to the current
Copy code
val bafo = bar({foo(it)})
but javascript treats functions as objects or something, so that's how it easily gets away with it
g
Isn't it what you can do with function reference?
Copy code
bar(::foo)
Functions in Kotlin are also objects, you just need reference syntax to get access to object
h
hmmm, i haven't used the
::
syntax for a couple years. forgot it existed. still don't know what it does
g
Literals are not easy... personally, I doubt it will be ever implemented but so far I like this Clojure adoption the most: https://github.com/Kotlin/KEEP/pull/112#issuecomment-419740049. Stuff like
Array<Int>
and
IntArray
is important but in perspective, Declarative is superior to Imperative. We need to offload accidental complexity that was introduced over the years.
WHAT
is superior to
HOW
. Foreach is better than for loop, because you don't see how it's implemented. That's why
listOf
tells you nothing about its implementation (HOW), because, frankly, nobody cares. In ideal world we don't want to care about
IntArray
as well. One day.... 😏
g
I agree with you in general like concept. just a lot of nuances that you cannot ignore when you have to implement it to a language with millions lines of code and used in thousands of projects and also remember about future evolution of the language, because small today may cause huge problems tomorrow
In ideal world
There is no ideal world, and Kotlin is not about ideal, it’s to be practical and pragmatic
g
Knowing the stars to shoot for helps to progress in less ideal world. Kotlin could have been just a better java but it already has some distinct functional foundation that might look questionable at the moment because it's not as efficient with the current collections as you'd do it imperatively. But step by step we'll have semantic collections, true immutability, typeclasses and maybe one day we'll ditch the object identity imposed by JVM to make all these things efficient... Boi, do I sound like a Rich Hickey now.. 🙈
g
not as efficient with the current collections as you’d do it imperatively
What do you mean?
g
There is this beatiful idea in FP that you can express your code as a composition of multiple functions avoiding state and mutability completely, right? The thing is that this theory goes hand in hand with smart collections, advanced VMs and compilers that know how to do lazy/deferred evaluations, reuse objects (hard on JVM because of object identity), etc. The reality is that if you start blindly using all these sweet
partition, window, plus, zip, etc
in kotlin you'll get a significant hit on performance. So, it's kind of there, begging to be used, then you check the implementation, see a lot of copying and most probably end up implement it in old imperative way, with mutable state. Idk, as an exercise, functional Pascal Triangle in kotlin https://pl.kotl.in/HkTog_ht4. That's a lot of allocations there simple smile . Supposedly, an advanced low level toolchain will be able to optimize it in a way, that you don't have to be concerned of your operator implementation and just write the code that is as close to formal specification as possible.
g
Kotlin is not pure functional language and not optimized for this use case obviously (it doesn’t have proper GC, type strcture etc)
And also FP is not about speed, in many cases for real-life performance optimizations or just for some use cases for functional language you need “ugly” imperative hacks
m
A lot of talk since I was last here. For array literals, kotlin 1.3 introduced then for annotations and intellij now recommends then. IIRC, the intent is to introduce array literal to the whole language but as per comments above, requires a bit more work under the covers, so will be a bit longer. intArray exists for efficiency (as mentioned) but there's no way (unless the compiler had an explicit check) to stop Array<Int>. It's valid code as one is typing the list. Agree it can be confusing. I do believe compiler will always infer IntArray so the only time you'd see Array<Int> would be someone manually applying it.
For FP and concerns of performance because of all the collection creation, consider using asStream. For small lists, it generally doesn't matter, but if it does, asStream can often help. There are initiatives started to have immutable lists that support FP list processing better, but keeping interop obviously makes that much harder.
But I think we all agree jetbrains is doing a great job with Kotlin. Java's not terrible, and it's slowly improving, but anytime I have to write Java, it feels like death by a thousand cuts. No major pain or damage, just little things that keep adding up. I joke that kotlin is Java 30 but right now... Jdk11 added val. Jdk12 switch is finally an expression and can use blocks for cases similar to when and others. So it's coming...
h
referring to the KEEP post @ghedeon, I think I would prefer
[1,2,3]
for lists. Arrays to be removed from Kotlin.
[1 to 1, 2 to 1]
or
[1:1, 2:1]
for maps and
{1,2,3}
for sets/collections.
@Mike
kotlin 1.3 introduced then for annotations and intellij now recommends then.
is
then
something added in 1.3? I'm confused. Not seeing it in google searches Also, I agree that java is getting a lot nicer to use, but it still lacks any feature that Kotlin doesn't already have (except.... array literals). So maybe it'll get there, but it seems like such a long way off.
m
Sorry, them. Meaning for array properties, one can use ["value1","value2"] in annotation values rather than arrayOf. Intent is to add this to general array construction AFAIK.
g
Arrays will never be removed from Kotlin, because it will not be Kotlin anymore, so doesn't make sense to discuss such proposal