# Add Kotlin Standard Library's functions: let & also

**URL:** <https://internals.rust-lang.org/t/add-kotlin-standard-librarys-functions-let-also/11933>\
**Category:** libs\
**Created:** [March 5, 2020, 12:30pm UTC](https://internals.rust-lang.org/t/add-kotlin-standard-librarys-functions-let-also/11933 "2020-03-05T12:30:02Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![moeKiwiSAMA](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/moekiwisama/32/6620_2.png) [@moeKiwiSAMA](https://internals.rust-lang.org/u/moeKiwiSAMA)\
**Post date:** [March 5, 2020, 12:30pm UTC](https://internals.rust-lang.org/t/add-kotlin-standard-librarys-functions-let-also/11933/1 "2020-03-05T12:30:02Z")

</div>

To better support method chaining, Rust could include the following trait, which can improve the user experience:

```rust
pub trait KtStd {
    fn let_imut<R, F>(&self, block: F) -> R where F: FnOnce(&Self) -> R;
    fn let_mut<R, F>(&mut self, block: F) -> R where F: FnMut(&mut Self) -> R;
    fn let_owned<R, F>(self, block: F) -> R where Self: Sized, F: FnOnce(Self) -> R;

    fn also_imut<F>(&self, block: F) -> &Self where F: FnOnce(&Self);
    fn also_mut<F>(&mut self, block: F) -> &mut Self where F: FnMut(&mut Self);
}

```

Before it:

```rust
let mut s = String::new();
stdin().read_line(&mut s).unwrap();
s. // do something.
println!("{}" s);

```

After:

```rust
String::new()
    .also_mut(|mut s| { stdin().read_line(&mut s).unwrap(); }) // return &mut s
    . // do some Method Channing.
    .let_imut(|s| println!("{}", s)) // return closure result

```

Here is already an implementation:

```rust
impl<T> KtStd for T {
    fn let_imut<R, F>(&self, block: F) -> R
    where
        F: FnOnce(&Self) -> R,
    {
        block(self)
    }
    fn let_mut<R, F>(&mut self, mut block: F) -> R
    where
        F: FnMut(&mut Self) -> R,
    {
        block(self)
    }
    fn let_owned<R, F>(self, block: F) -> R
    where
        Self: Sized,
        F: FnOnce(Self) -> R,
    {
        block(self)
    }

    fn also_imut<F>(&self, block: F) -> &Self
    where
        F: FnOnce(&Self),
    {
        block(self);
        self
    }
    fn also_mut<F>(&mut self, mut block: F) -> &mut Self
    where
        F: FnMut(&mut Self),
    {
        block(self);
        self
    }
}

```

---

<div class="post-metadata">

**Author:** ![Ixrec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ixrec/32/6754_2.png) [@Ixrec](https://internals.rust-lang.org/u/Ixrec)\
**Post date:** [March 5, 2020, 12:34pm UTC](https://internals.rust-lang.org/t/add-kotlin-standard-librarys-functions-let-also/11933/2 "2020-03-05T12:34:27Z")

</div>

How is this an improvement? The "after" snippet looks like it has exactly the same "real code" as the "before" snippet, except wrapped in closures.

---

<div class="post-metadata">

**Author:** ![hzqd](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hzqd/32/8887_2.png) [@hzqd](https://internals.rust-lang.org/u/hzqd)\
**Post date:** [March 5, 2020, 12:50pm UTC](https://internals.rust-lang.org/t/add-kotlin-standard-librarys-functions-let-also/11933/3 "2020-03-05T12:50:58Z")

</div>

Defining variables and moving the cursor frequently will interrupt the developer's thinking. If this feature is available, the developer's thinking will be natural and spontaneous.

---

<div class="post-metadata">

**Author:** ![jer](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jer/32/1009_2.png) [@jer](https://internals.rust-lang.org/u/jer)\
**Post date:** [March 5, 2020, 2:07pm UTC](https://internals.rust-lang.org/t/add-kotlin-standard-librarys-functions-let-also/11933/4 "2020-03-05T14:07:52Z")

</div>

This seems _very_ subjective. I'm with lxrec in that this is no improvement at all. It suddenly uses closures where none are needed. It's longer. It uses naming that's no where near common (`imut`). And additionally it doesn't allow anything that's not already possible (including users implementing this themselves if they feel the need for it)

---

<div class="post-metadata">

**Author:** ![elidupree](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/elidupree/32/4304_2.png) [@elidupree](https://internals.rust-lang.org/u/elidupree)\
**Post date:** [March 5, 2020, 2:13pm UTC](https://internals.rust-lang.org/t/add-kotlin-standard-librarys-functions-let-also/11933/5 "2020-03-05T14:13:51Z")

</div>

I absolutely appreciate the motivation for this, and I've wanted a similar thing in the past. However, there's no need for this to go in the standard library; it could just as easily be an external crate. (You could even publish it yourself!)

As a more minor point, in the current implementation, the naming of the methods is inconsistent with Rust precedent and feels nonintuitive to me personally. But I'm sure it would be possible to find different names that would improve upon that.

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [March 5, 2020, 2:48pm UTC](https://internals.rust-lang.org/t/add-kotlin-standard-librarys-functions-let-also/11933/6 "2020-03-05T14:48:26Z")

</div>

`let_ref` would be more idiomatically consistent. And I agree this can be a crate -- it's a bit like [`tap`](https://crates.io/crates/tap).

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [March 5, 2020, 2:56pm UTC](https://internals.rust-lang.org/t/add-kotlin-standard-librarys-functions-let-also/11933/7 "2020-03-05T14:56:33Z")

</div>

[tap](https://docs.rs/tap/0.4.0/tap/) already exists for `fn TapOos::tap<R>(self, f: impl FnOnce(&mut Self) -> R)) -> Self`. I've used it a few times before.

This is actually also enough for the by-ref case: since all `T: Sized` impl `TapOps`, you can `<&_>::tap` for the by-ref case.

Strangely enough, I actually think this functionality _might_ be able to fit in std. Why? It's in a similar situation to `dbg!`: it's the kind of tiny helper that you might use and enjoy using if you have it, but you're unlikely to reach to a crate to provide it, because just doing it without a crate and a simple scope is just as easy.

Though it really isn't as useful as in Kotlin: you still have to come up with a name to be used in the closure, so you aren't saving a name. (In Kotlin, .`let`/.`also` provide access as the receiver `self` or the unnamed closure arg `it`, though I don't recall which is which.)

However, adding a method to _all types_ is an invasive change for the std lib prelude. Because of that, it'd have to be a non-prelude trait. But at that point, there's little reason anymore to have this in std rather than a crate.

---

<div class="post-metadata">

**Author:** ![Jon-Davis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jon-davis/32/5453_2.png) [@Jon-Davis](https://internals.rust-lang.org/u/Jon-Davis)\
**Post date:** [March 5, 2020, 6:25pm UTC](https://internals.rust-lang.org/t/add-kotlin-standard-librarys-functions-let-also/11933/8 "2020-03-05T18:25:17Z")

</div>

I do like concept, I sometimes have to break up a chain because one of the functions I want to invoke doesn't return self, although if [postfix macros](https://github.com/rust-lang/rfcs/pull/2442) ever materialize this could possibly become a macro. Which would remove the need to impl a trait on every type.

```rust
String::new()
  .then!(mut s, stdin().read_line(&mut s).unwrap())
  .then!(s, println!("{}", s))

```

---

<div class="post-metadata">

**Author:** ![jjpe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jjpe/32/9779_2.png) [@jjpe](https://internals.rust-lang.org/u/jjpe)\
**Post date:** [March 5, 2020, 7:59pm UTC](https://internals.rust-lang.org/t/add-kotlin-standard-librarys-functions-let-also/11933/9 "2020-03-05T19:59:25Z")

</div>

How are these 2 snippets semantically different?

```rust
String::new()
  .then!(mut s, stdin().read_line(&mut s).unwrap())
  .then!(s, println!("{}", s))

```

```rust
let mut s: String::new();
stdin().read_line(&mut s).unwrap();
println!("{}", s);

```

I ask, because the 2 examples have an equal number of SLOC, and line-for-line seem to have identical semantics. So it doesn't cut boilerplate, and I'm not even sure it's easier to type. So what advantage does the 1st snippet have that I'm missing here? That it might be an expression\*?

\*I'm not sure if it would be an expression at all, since it looks like the macro might perhaps have some influence over that, depending on design and implementation.

---

<div class="post-metadata">

**Author:** ![atagunov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/atagunov/32/5877_2.png) [@atagunov](https://internals.rust-lang.org/u/atagunov)\
**Post date:** [March 5, 2020, 8:45pm UTC](https://internals.rust-lang.org/t/add-kotlin-standard-librarys-functions-let-also/11933/10 "2020-03-05T20:45:29Z")

</div>

> [@jjpe](#):
>
> How are these ... different?

...surprisingly 1st indeed feels easier to grasp

---

<div class="post-metadata">

**Author:** ![Jon-Davis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jon-davis/32/5453_2.png) [@Jon-Davis](https://internals.rust-lang.org/u/Jon-Davis)\
**Post date:** [March 5, 2020, 11:56pm UTC](https://internals.rust-lang.org/t/add-kotlin-standard-librarys-functions-let-also/11933/11 "2020-03-05T23:56:23Z")

</div>

I agree with you. I was using the original example with the postfix idea for contrast.

My argument wasn't whether or not this pattern is useful in the original example. But that if the pattern was desired in some situation, then it could be handled using another potential feature already in discussion. Whether or not a `then!()` macro, or any other generic `map!()` or `filter!()` macro belongs in std is an argument I will defer.

---

<div class="post-metadata">

**Author:** ![jhpratt](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jhpratt/32/11640_2.png) [@jhpratt](https://internals.rust-lang.org/u/jhpratt)\
**Post date:** [March 6, 2020, 12:10am UTC](https://internals.rust-lang.org/t/add-kotlin-standard-librarys-functions-let-also/11933/12 "2020-03-06T00:10:49Z")

</div>

Keep in mind that RFC 2442 (postfix macros) does **not** define typed postfix macros. `.then!()` _may_ be generalizable, but the vast majority of postfix macros would not be. I'd love to see typed postfix macros as much as anyone else, but it would require a fundamental shift in how macros are processed.

---

<div class="post-metadata">

**Author:** ![dhm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dhm/32/4879_2.png) [@dhm](https://internals.rust-lang.org/u/dhm)\
**Post date:** [March 6, 2020, 12:28pm UTC](https://internals.rust-lang.org/t/add-kotlin-standard-librarys-functions-let-also/11933/13 "2020-03-06T12:28:22Z")

</div>

> [@CAD97](#):
>
> This is actually also enough for the by-ref case: since all `T: Sized` impl `TapOps` , you can `<&_>::tap` for the by-ref case.

This is an important difference to `let_ref` (renamed from `imut` for consistency) and `let_mut` helpers: these use anonymous / universal lifetimes for their closure, meaning that doing

```rust
[42, 27]
    .let_ref(|it| &it[0]) // HRTB lifetime gives `it` the usability (rather the lack thereof) of a local

```

would fail with a lifetime error.

The signatures for `let_ref` and `let_mut` need to be:

```rust
pub trait KtStd {
    // allow `R` to depend on `'a`
    fn let_ref<'a, R, F>(&'a self, then: F) -> R where F: FnOnce(&'a Self) -> R;
    fn let_mut<'a, R, F>(&'a mut self, then: F) -> R where F: FnMut(&'a mut Self) -> R;

```

Regarding the naming, `with` is more consistent for this style of patterns:

```rust
.with_ref(|it| ...) // sugar for `(&<expr>).with(|it| ...)`, much like `.iter()` _w.r.t._ `.into_iter()`
.with_mut(|it| ...) // ditto for `&mut` and `iter_mut()`
.with(|it| ...) // may be shadowed by inherent `with`s (_e.g._, `thread_local!`'s),
                // so a `with_owned` alias could be added to disambiguate.

```

Also, we'd need the `try_with...` fallible variants.

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [March 6, 2020, 1:49pm UTC](https://internals.rust-lang.org/t/add-kotlin-standard-librarys-functions-let-also/11933/14 "2020-03-06T13:49:53Z")

</div>

Relatedly, sometimes when working on the error message API in rustc, I find myself wanting something like:

```rust
self.struct_span_err(...).with(|err| {
    err.span_label(...)
       .span_label(...);
})

```

where `with` has the signature as `fn with(mut self, modify: FnOnce(&mut Self)) -> Self`.

The main point of this is that I have a builder taking in and returning `&mut Self`, but I don't want to give up access to the builder by-value.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [June 4, 2020, 1:49pm UTC](https://internals.rust-lang.org/t/add-kotlin-standard-librarys-functions-let-also/11933/15 "2020-06-04T13:49:56Z")

</div>

Closed on June 4, 2020, 1:49pm UTC

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
