4 ms·
It's idiomatic in Kotlin as well! https://kotlinlang.org/docs/scope-functions.html https://kotlinlang.org/docs/scope-functions.html
by aabdelhafez 10mo ago
It's idiomatic in Kotlin as well!
https://kotlinlang.org/docs/scope-functions.html https://kotlinlang.org/docs/scope-functions.html
- simon_void 10mo agoI agree, i started with (scope) blocks in Rust, but keep the habit in Kotlin win the run - scope-function. Since run takes no arguments, it feels like the closest equivalent to Rust scopes (compared to other Korlin scope functions, which also keep their local variables from polluting the rest of the function body).
- zaphirplane 10mo agoSo many options why oh why. let run with also apply
- jeroenhd 10mo agoEach does different things, and Rust also has plenty of them. and_then(), or(), or_else(), then(), the list goes on. Kotlin just implements them more widely. Actually, Kotlin's with() and apply() are more powerful than what Rust can provide. Then again, Rust isn't designed with OO in mind, so you probably shouldn't use those patterns in Rust anyway.
- saghm 10mo agoI think you've misunderstood the point they were making by addressing the number as if it was the only concern and then only mentioning the actual point they were trying to make as if it were an incidental afterthought. I don't think it's likely they're criticizing five functions in the standard library is too many, but that having five special functions with certain semantics that only apply to them is too many. The methods you mention in Rust are all in the first category; you could easily write them yourself for any type you define without needing to resort to wrapping any of them. It's not clear to me that someone could write a function in Kotlin with special scoping semantics around an object without resorting to wrapping one of those functions.
- jeroenhd 10mo agoThe Kotlin functions are actually quite easy to write, they're all written in standard Kotlin. also: https://github.com/JetBrains/kotlin/blob/2.3.0/libraries/stdlib/src/kotlin/util/Standard.kt#L99 https://github.com/JetBrains/kotlin/blob/2.3.0/libraries/std... apply: https://github.com/JetBrains/kotlin/blob/2.3.0/libraries/stdlib/src/kotlin/util/Standard.kt#L83 https://github.com/JetBrains/kotlin/blob/2.3.0/libraries/std... let: https://github.com/JetBrains/kotlin/blob/2.3.0/libraries/stdlib/src/kotlin/util/Standard.kt#L114 https://github.com/JetBrains/kotlin/blob/2.3.0/libraries/std... with: https://github.com/JetBrains/kotlin/blob/2.3.0/libraries/stdlib/src/kotlin/util/Standard.kt#L69 https://github.com/JetBrains/kotlin/blob/2.3.0/libraries/std... run (two overloads): https://github.com/JetBrains/kotlin/blob/2.3.0/libraries/stdlib/src/kotlin/util/Standard.kt#L41 https://github.com/JetBrains/kotlin/blob/2.3.0/libraries/std... and https://github.com/JetBrains/kotlin/blob/2.3.0/libraries/stdlib/src/kotlin/util/Standard.kt#L55 https://github.com/JetBrains/kotlin/blob/2.3.0/libraries/std... These all heavily rely on Kotlin's ability to write an extension function for any class. When you write `with(x) { something() }` you're extending the type of `x` (be that int, List<String>, or SomeObject) with an anonymous method, and passing that as a second parameter. Consider the signature here: public inline fun <T, R> with(receiver: T, block: T.() -> R): R The first object is a generic object T, which can be anything. The second is a member function of T that returns R, which again can be just about anything, as long as it operates on T and returns R. Let does it kind of diferently: public inline fun <T, R> T.let(block: (T) -> R): R This is an extension method that applies to every single class as T isn't restricted, so as long as this function is in scope (it's in the standard library so it will be), every single object will have a let() method. The only parameter, block, is a lambda that takes T and returns R. So for instance: val x = makeFoo() with (x) { bar = 4 } is syntactic sugar for something like: fun Foo.anonymous() { this.bar = 4 } val x = makeFoo() with(x, Foo::anonymous) You could absolutely write any of these yourself. For instance, consider this quick example I threw together: https://pl.kotl.in/S-pHgvxlX https://pl.kotl.in/S-pHgvxlX The type inference is doing a lot of heavy lifting, i.e. taking a lambda and automatically turning it into an anonymous extension function, but it's nothing that you cannot do yourself. In fact, a wide range of libraries write what might look like macros in Kotlin by leveraging this and the fact you can define your own inline operators (i.e. https://pl.kotl.in/TZB0zA1Jr https://pl.kotl.in/TZB0zA1Jr). This isn't possible in many other languages because taking a generic type definition and letting it possibly apply to every single existing type is not exactly popular. Combined with Kotlin's ability to extend nullable types (i.e. this = null) as well makes for a language system that wouldn't work in many other flexible languages.
- zaphirplane 9mo agoSurely you have to appreciate or else are a different from then examples I gave, the 6 or so kotlin are effectively call a closure with a captured object, with some variation on the return value