0

One of the conveniences offered by JavaScript's jQuery is the ability to chain methods like so:

​$(document).ready(function() {
    $('#dvContent')
        .addClass('dummy')
        .css('color', 'red')
        .fadeIn('slow');
});​

Instead of the more verbose non-chained way of writing the same:

$(document).ready(function() {
    $('#dvContent').addClass('dummy');
    $('#dvContent').css('color', 'red');
    $('#dvContent').fadeIn('slow');
});​

Above jQuery code courtesy of jquerybyexample.net.

This is possible because the $(selector) function in jQuery returns a jQuery reference to whatever is indicated by selector, and it is standard for jQuery functions that don't return some type of value (i.e. would otherwise be void) to return the jQuery reference from $(selector) so that the next function in the chain can make use of it.

In Rust, however, this seems impossible.

Let's implement this in pseudo-Rust:

fn $(selector: &Selector) -> JQueryReference {
    JQuery::get(selector)
}

So far so good...

impl Chainable for JQueryReference {
    fn addClass(&self, class: String) -> Self {
        deep_frontendy_stuff_add_class(&self, class);
        self
    }
}

Ooh, no bueno, that deep_frontendy_stuff_add_class() function can't modify self. Oh I know, I'll just make the reference mutable!

impl Chainable for JQueryReference {
    fn addClass(&mut self, class: String) -> Self {
        deep_frontendy_stuff_add_class(&mut self, class);
        self
    }
}

Cool, that worked! But wait, what if I want to go old school and not use the fancy chained types?

$("#dvContent".to_string()).addClass("dummy".to_string());
$("#dvContent".to_string()).css("color".to_string(), "red".to_string());

Nooooooooo! The borrow checker is at it again!

How do I implement such behavior, and if you wouldn't mind, please be as descriptive as possible about why. This question is really an example to help understand the language.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
TheEnvironmentalist
  • 2,694
  • 2
  • 19
  • 46
  • 1
    *The borrow checker is at it again!* — how? there are no errors in this question. – Shepmaster Oct 17 '18 at 01:41
  • 1
    Have you already read [How to write an idiomatic build pattern with chained method calls in Rust?](https://stackoverflow.com/q/41617182/155423) and [How to use the chained builder pattern in a loop without creating a compiler error?](https://stackoverflow.com/q/45517265/155423) – Shepmaster Oct 17 '18 at 01:44
  • 1
    Please review how to create a [MCVE] and then [edit] your question to include it. Your "pseudo-Rust" doesn't need to be and actively makes it *harder* for us to see what the problem is. Try to produce something that reproduces your error on the [Rust Playground](https://play.rust-lang.org) or you can reproduce it in a brand new Cargo project. There are [Rust-specific MCVE tips](//stackoverflow.com/tags/rust/info) as well. – Shepmaster Oct 17 '18 at 01:51
  • 3
    Possible duplicate of [How to write an idiomatic build pattern with chained method calls in Rust?](https://stackoverflow.com/q/41617182/608639) – jww Oct 17 '18 at 05:22
  • @Shepmaster My apologies for the lack of clarity, as I said at the end of the question (and as I probably should have said at the start), the emphasis isn't on the chained calls at all, it's on the borrow checker, and basically understanding how code can be written that is both borrow-checker-friendly and effective, as sometimes it feels like the borrow checker disallows every possible solution to a problem – TheEnvironmentalist Oct 17 '18 at 09:58

0 Answers0