Public review of the Standard Library APIs [Closed]

The changed behavior of split() is very much intentional. Using a regex to split has non-trivial performance costs and surprising behavior in cases when a symbol you want to split with has special semantics in a regexp and needs to be escaped. We have explicitly separated methods which take a simple String (and don’t do any fancy regexp matching) and which take a Regex (which could be pre-compiled and stored as a constant).

Utils

These would be nice to have:

Throwable.rootCause() (as in Guava)

Throwable.stackTraceAsString() (as in Guava)

As I happen to just have stated in the Slack channel: I’m a bit dual about ThreadLocal. The property delegate is easily created but any (required) cleanup is easily forgotten, thus adding something like ThreadLocal delegates to the stdlib also introduces the risk of being used while not fully understood, hence leading to potential memory leaks.

That cleaning up also means you need to have a reference to the delegate itself in order to call some remove function. Or allow nulls to null the value out but that won’t work with vals and defies the purpose of the type system.

I disagree strongly that it is more logical. Conceptually, an array or list is like a map in that there is some value you use to refer to the values in the collection and then there are the values in the collection. So the index is analogous to the key in a map. I expect it to be index, value just as when iterating over entries in a map I expect it to be key, value and not the reverse.

Good points. Probably better not added to stdlib (and removed from my wish list).

Groovy and Scala have withIndex methods, which put the index last. Ceylon and Kotlin have indexed methods, which put the index first. Looking at it now, both approaches make sense.

Did anything come out of this, JetBrains? Most of all, I constantly find myself in need of a variant of apply whose function takes a parameter rather than being an extension function. I have my own applyIt, but such a fundamental primitive should be in stdlib.

apply can be used as more than an object initializer. I, for one, use it in unit tests to avoid giving test data trivial names. Compare:

val rectangle = Rectangle(1, 2, 3, 4)
assert(rectangle.contains(Point(1,2))

and

Rectangle(1,2,3,4)
    .apply { assert(contains(Point(1,2)) }
1 Like

We are not renaming any of existing scope functions, but we may provide later such variant of apply. The name of that function is discussable. I’ve reopened issue KT-6903 to track it.

@ilya.gorbunov That’s great to hear. What about the duplication between with and T.run, which are completely equivalent, except that one is a function and the other an Any? extension method? I’d prefer to write foo.with { ... }, as this name, which is also used in other languages, resonates much more with me than foo.run { ... }.

I’ve no idea where to put this though it is now Jan 19.

The documentation of “return” is wrong, see:

https://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/src/generated/_Ranges.kt#L1089

and also the produced doc:

Should be:

@return this value if it’s less than or equal to the [maximumValue] or the [maximumValue] otherwise.

1 Like

After some discussion, we have decided not to drop zeroth group from the groupValues list, so that the same index value would refer to the same group both in groups and in groupValues.

The downside of this decision is that the groupValues list becomes less convenient for destructuring assignment. An intended way to destructure no longer works:
val (group1, group2) = match.groupValues, because the first value now is the match value itself and not the first group value.

In order to make destructuring assignment possible, we’re introducing another property MatchResult.destructured, which only provides component1, component2component10 methods to satisfy the destructuring convention. Thus the usage would be:
val (group1, group2) = match.destructured

Thanks everyone! Now this call is closed