# Writing code with Rust cost so many lines

**URL:** <https://internals.rust-lang.org/t/writing-code-with-rust-cost-so-many-lines/15304>\
**Category:** community\
**Created:** [September 9, 2021, 11:02am UTC](https://internals.rust-lang.org/t/writing-code-with-rust-cost-so-many-lines/15304 "2021-09-09T11:02:14Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![seasonyuu](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/seasonyuu/32/8530_2.png) [@seasonyuu](https://internals.rust-lang.org/u/seasonyuu)\
**Post date:** [September 9, 2021, 11:02am UTC](https://internals.rust-lang.org/t/writing-code-with-rust-cost-so-many-lines/15304/1 "2021-09-09T11:02:14Z")

</div>

Why the code looks so long while writing with Rust? With the same function writing in Kotlin , it seems so easy to read and write. I think that I might be wrong with this program. What's wrong with this??

Rust version

```rust
struct Life {
    is_dead: bool,
}
impl Life {
    fn new() -> Life {
        Life {
            is_dead: false
        }
    }
    fn is_alive(&self) -> bool {
        return !self.is_dead;
    }
    fn die_now(&self) -> Life {
        return Life {
            is_dead: true,
        }
    }
}
trait Fittable {
    fn fit(&self);
}
trait Yelled {
    fn yell(&self);
}
struct Cat {
    life: Life,
}
impl Fittable for Cat {
    fn fit(&self) {
        if self.life.is_alive() {
            println!("Fish");
        } else {
            println!("You cannot fit a dead cat");
        }
    }
}
impl Yelled for Cat {
    fn yell(&self) {
        if self.life.is_alive() {
            println!("Meow");
        } else {
            println!("A dead cat cannot yell");
        }
    }
}
impl Cat {
    fn new() -> Cat {
        Cat {
            life: Life::new()
        }
    }
    fn die_now(&self) -> Cat {
        Cat {
            life: self.life.die_now(),
            ..*self
        }
    }
}
struct Dog {
    life: Life,
}
impl Fittable for Dog {
    fn fit(&self) {
        if self.life.is_alive() {
            println!("Bone");
        } else {
            println!("You cannot fit a dead dog");
        }
    }
}
impl Yelled for Dog {
    fn yell(&self) {
        if self.life.is_alive() {
            println!("Woof");
        } else {
            println!("A dead dog cannot yell");
        }
    }
}
impl Dog {
    fn new() -> Dog {
        Dog {
            life: Life::new()
        }
    }
    fn die_now(&self) -> Dog {
        Dog {
            life: self.life.die_now(),
            ..*self
        }
    }
}
fn main() {
    let cat = Cat::new();
    println!("cat is alive? {}", cat.life.is_alive());
    cat.fit();
    cat.yell();
    let cat = cat.die_now();
    println!("cat is alive? {}", cat.life.is_alive());
    cat.fit();
    cat.yell();
    let dog = Dog::new();
    println!("dog is alive? {}", dog.life.is_alive());
    dog.fit();
    dog.yell();
    let dog = dog.die_now();
    println!("dog is alive? {}", dog.life.is_alive());
    dog.fit();
    dog.yell();
}

```

Kotlin Version:

```kotlin
abstract class Life {
    private var isDead = false;
    fun isAlive(): Boolean {
        return !this.isDead;
    }
    fun dieNow() {
        this.isDead = true;
    }
}
interface Fittable {
    fun fit();
}
interface Yelled {
    fun yell();
}
class Cat: Life, Fittable, Yelled {
    constructor()
    override fun fit() {
        if (this.isAlive()) {
            println("Fish");
        } else {
            println("You cannot fit a dead cat");
        }
    }
    override fun yell() {
        if (this.isAlive()) {
            println("Meow");
        } else {
            println("A dead cat cannot yell");
        }
    }
}
class Dog: Life, Fittable, Yelled {
    constructor()
    override fun fit() {
        if (this.isAlive()) {
            println("Bone");
        } else {
            println("You cannot fit a dead dog");
        }
    }
    override fun yell() {
        if (this.isAlive()) {
            println("Woof");
        } else {
            println("A dead dog cannot yell");
        }
    }
}
fun main() {
    val cat = Cat();
    println("cat is alive? ${cat.isAlive()}");
    cat.fit();
    cat.yell();
    cat.dieNow();
    println("cat is alive? ${cat.isAlive()}");
    cat.fit();
    cat.yell();
    val dog = Dog();
    println("dog is alive? ${dog.isAlive()}");
    dog.fit();
    dog.yell();
    dog.dieNow();
    println("dog is alive? ${dog.isAlive()}");
    dog.fit();
    dog.yell();
}

```

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [September 9, 2021, 11:28am UTC](https://internals.rust-lang.org/t/writing-code-with-rust-cost-so-many-lines/15304/2 "2021-09-09T11:28:59Z")

</div>

Hi and welcome to this forum. This is the “internals” forum where we discuss changes to the design of the Rust language and standard library, and sometimes also talk about implementation details of the rustc compiler, or other things related to contributing to the development of rustc.

Your questions seems more about trying to get a better understanding of the language Rust, and I guess you’re also asking how your “program” (though it’s arguably more of an object-oriented-language toy-example demonstration, not exactly a realistic “program”) could be written more concisely and/or more ideomatically in Rust.

For questions like these, I suggest you move over to the “users” forum at [https://users.rust-lang.org/](https://users.rust-lang.org/). That’s the more appropriate place for your question and you can expect more and better answers over there.

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [September 9, 2021, 12:05pm UTC](https://internals.rust-lang.org/t/writing-code-with-rust-cost-so-many-lines/15304/3 "2021-09-09T12:05:46Z")

</div>

In any case, let me give you a quick answer here.

Rust doesn’t fully support object-oriented programming. In particular, we value separation of data and behavior. We don’t have the kind of inheritance that (abstract) classes in Java offer, where you inherit _both_ fields and methods together.

In situations where this form of inheritance works, you can often achieve the same thing with delegation. In fact, your Rust code _does_ do some form of delegation, unfortunately this comes with boilerplate code, as you noticed.

One solution to boilerplate code in Rust is to use macros. Before we go there, in a first step to coming closer to your Kotlin code, we should change `die_now` from `fn die_now(&self) -> Self` to `fn die_now(&mut self) -> ()`. (And also let’s remove some more unnecessary `return` keywords.)

```rust
struct Life {
    is_dead: bool,
}
impl Life {
    fn new() -> Life {
        Life { is_dead: false }
    }
    fn is_alive(&self) -> bool {
        !self.is_dead
    }
    fn die_now(&mut self) {
        self.is_dead = true
    }
}
trait Fittable {
    fn fit(&self);
}
trait Yelled {
    fn yell(&self);
}
struct Cat {
    life: Life,
}
impl Fittable for Cat {
    fn fit(&self) {
        if self.life.is_alive() {
            println!("Fish");
        } else {
            println!("You cannot fit a dead cat");
        }
    }
}
impl Yelled for Cat {
    fn yell(&self) {
        if self.life.is_alive() {
            println!("Meow");
        } else {
            println!("A dead cat cannot yell");
        }
    }
}
impl Cat {
    fn new() -> Cat {
        Cat { life: Life::new() }
    }
    fn die_now(&mut self) {
        self.life.die_now()
    }
}
struct Dog {
    life: Life,
}
impl Fittable for Dog {
    fn fit(&self) {
        if self.life.is_alive() {
            println!("Bone");
        } else {
            println!("You cannot fit a dead dog");
        }
    }
}
impl Yelled for Dog {
    fn yell(&self) {
        if self.life.is_alive() {
            println!("Woof");
        } else {
            println!("A dead dog cannot yell");
        }
    }
}
impl Dog {
    fn new() -> Dog {
        Dog { life: Life::new() }
    }
    fn die_now(&mut self) {
        self.life.die_now()
    }
}
fn main() {
    let mut cat = Cat::new();
    println!("cat is alive? {}", cat.life.is_alive());
    cat.fit();
    cat.yell();
    cat.die_now();
    println!("cat is alive? {}", cat.life.is_alive());
    cat.fit();
    cat.yell();
    let mut dog = Dog::new();
    println!("dog is alive? {}", dog.life.is_alive());
    dog.fit();
    dog.yell();
    dog.die_now();
    println!("dog is alive? {}", dog.life.is_alive());
    dog.fit();
    dog.yell();
}

```

* * *

Now, let’s use macros. There’s a few crates out there that can help with macros to reduce boilerplate. Let’s start with `new` methods. While in this case, you could technically probably just use `::default` instead of `::new` and derive the [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) implementations, it’s good style to still also have a `new` method. Let’s use the [`derive-new`](https://docs.rs/derive-new) crate to help out.

```rust
use derive_new::new;

#[derive(new)]
struct Life {
    #[new(value = "false")]
    is_dead: bool,
}
impl Default for Life {
    fn default() -> Self {
        Self::new()
    }
}
impl Life {
    fn is_alive(&self) -> bool {
        !self.is_dead
    }
    fn die_now(&mut self) {
        self.is_dead = true
    }
}
trait Fittable {
    fn fit(&self);
}
trait Yelled {
    fn yell(&self);
}

#[derive(new, Default)]
struct Cat {
    #[new(default)]
    life: Life,
}
impl Fittable for Cat {
    fn fit(&self) {
        if self.life.is_alive() {
            println!("Fish");
        } else {
            println!("You cannot fit a dead cat");
        }
    }
}
impl Yelled for Cat {
    fn yell(&self) {
        if self.life.is_alive() {
            println!("Meow");
        } else {
            println!("A dead cat cannot yell");
        }
    }
}
impl Cat {
    fn die_now(&mut self) {
        self.life.die_now()
    }
}

#[derive(new, Default)]
struct Dog {
    #[new(default)]
    life: Life,
}
impl Fittable for Dog {
    fn fit(&self) {
        if self.life.is_alive() {
            println!("Bone");
        } else {
            println!("You cannot fit a dead dog");
        }
    }
}
impl Yelled for Dog {
    fn yell(&self) {
        if self.life.is_alive() {
            println!("Woof");
        } else {
            println!("A dead dog cannot yell");
        }
    }
}
impl Dog {
    fn die_now(&mut self) {
        self.life.die_now()
    }
}
fn main() {
    let mut cat = Cat::new();
    println!("cat is alive? {}", cat.life.is_alive());
    cat.fit();
    cat.yell();
    cat.die_now();
    println!("cat is alive? {}", cat.life.is_alive());
    cat.fit();
    cat.yell();
    let mut dog = Dog::new();
    println!("dog is alive? {}", dog.life.is_alive());
    dog.fit();
    dog.yell();
    dog.die_now();
    println!("dog is alive? {}", dog.life.is_alive());
    dog.fit();
    dog.yell();
}

```

Now, onto the `die_now` method. You’re delegating manually here, also you’ve actually skipped the opportunity to add the `is_alive` method to `Cat`/`Dog`. To begin with out Rust solution, let’s separate behavior from data first, but turning `Life` into a trait and a struct:

```rust
struct LifeStruct {
    #[new(value = "false")]
    is_dead: bool,
}
trait Life {
    fn is_alive(&self) -> bool;
    fn die_now(&mut self);
}

```

and implement it

```rust
impl Life for LifeStruct {
    fn is_alive(&self) -> bool {
        !self.is_dead
    }
    fn die_now(&mut self) {
        self.is_dead = true;
    }
}

```

Now we can use a crate that spares us boilerplate for delegation, e.g. [`ambassador`](https://github.com/hobofan/ambassador), in order to create trait implementations of `Life` for `Cat` and `Dog` as-well.

All we need to do is add an annotation on the trait

```rust
#[delegatable_trait]
trait Life {
    fn is_alive(&self) -> bool;
    fn die_now(&mut self);
}

```

and a derive and annotation on the structs, e.g.

```rust
#[derive(new, Default, Delegate)]
#[delegate(Life)]
struct Cat {
    #[new(default)]
    life: LifeStruct,
}

```

* * *

The `Cargo.toml` file now contains a section

```rust
[dependencies]
ambassador = "0.2.1"
derive-new = "0.5.9"

```

and the full code is

```rust
use ambassador::{delegatable_trait, Delegate};
use derive_new::new;

#[derive(new)]
struct LifeStruct {
    #[new(value = "false")]
    is_dead: bool,
}
impl Default for LifeStruct {
    fn default() -> Self {
        Self::new()
    }
}

#[delegatable_trait]
trait Life {
    fn is_alive(&self) -> bool;
    fn die_now(&mut self);
}
impl Life for LifeStruct {
    fn is_alive(&self) -> bool {
        !self.is_dead
    }
    fn die_now(&mut self) {
        self.is_dead = true;
    }
}

trait Fittable {
    fn fit(&self);
}
trait Yelled {
    fn yell(&self);
}

#[derive(new, Default, Delegate)]
#[delegate(Life)]
struct Cat {
    #[new(default)]
    life: LifeStruct,
}
impl Fittable for Cat {
    fn fit(&self) {
        if self.is_alive() {
            println!("Fish");
        } else {
            println!("You cannot fit a dead cat");
        }
    }
}
impl Yelled for Cat {
    fn yell(&self) {
        if self.is_alive() {
            println!("Meow");
        } else {
            println!("A dead cat cannot yell");
        }
    }
}

#[derive(new, Default, Delegate)]
#[delegate(Life)]
struct Dog {
    #[new(default)]
    life: LifeStruct,
}
impl Fittable for Dog {
    fn fit(&self) {
        if self.is_alive() {
            println!("Bone");
        } else {
            println!("You cannot fit a dead dog");
        }
    }
}
impl Yelled for Dog {
    fn yell(&self) {
        if self.is_alive() {
            println!("Woof");
        } else {
            println!("A dead dog cannot yell");
        }
    }
}

fn main() {
    let mut cat = Cat::new();
    println!("cat is alive? {}", cat.is_alive());
    cat.fit();
    cat.yell();
    cat.die_now();
    println!("cat is alive? {}", cat.is_alive());
    cat.fit();
    cat.yell();
    let mut dog = Dog::new();
    println!("dog is alive? {}", dog.is_alive());
    dog.fit();
    dog.yell();
    dog.die_now();
    println!("dog is alive? {}", dog.is_alive());
    dog.fit();
    dog.yell();
}

```

---

<div class="post-metadata">

**Author:** ![Volker\_Weissmann](https://avatars.discourse-cdn.com/v4/letter/v/c2a13f/32.png) [@Volker\_Weissmann](https://internals.rust-lang.org/u/Volker_Weissmann)\
**Post date:** [September 9, 2021, 3:54pm UTC](https://internals.rust-lang.org/t/writing-code-with-rust-cost-so-many-lines/15304/4 "2021-09-09T15:54:00Z")

</div>

My 2 cents (I'm just a user)

1. This belongs to [https://users.rust-lang.org/](https://users.rust-lang.org/)
2. Rust is usually way more lines than many other languages. I also use Python and Julia and those are way shorter. Rust has many strengths, but shortness is not one of them, it was not a design goal and many tradeoffs were made that made rust code longer, but better in a different way instead. That being said, I disagree with the thesis that "number of lines" equals "time to write". The biggest factor in how much time is needed to write an application is not how fast you can type, but how easy it is to debug and read. And rust is way easier to debug, many problems that take me half an hour in C++ or julia to debug are a simple compile error in rust that can be found and fixed in a minute. Rustc's error messages are really nice. Rust code is also easier to read, because of `rust-analyzer`. In Vscode, (if the correct extensions are installed and configured) you can put your cursor on a function call, press F12 (a.k.a Go To Definition) and the cursor will jump to the function definition. Similar features exists for other languages, but most of them are way less reliable than `rust-analyzer`.

About your example:

1. Always run `cargo clippy` and fix the warnings
2. As clippy suggests, the return keyword and the semicolon can be emitted, `expr` is equivalent to `return expr;`
3. As steffahn has noted, some code can be shortened (and made more similar than the Kotlin variant) by mutating an Object instead of constructing a new one:

```rust
    impl Life {
    ...
        fn die_now(&mut self) {
            self.is_dead = true;
        }
    }
    impl Cat {
        ...
        fn die_now(&mut self) {
            self.life.die_now();
        }
    }
    fn main() {
        let mut cat = Cat::new();
        println!("cat is alive? {}", cat.life.is_alive());
        cat.fit();
        cat.yell();
        cat.die_now();
        println!("cat is alive? {}", cat.life.is_alive());
        cat.fit();
        cat.yell();
    }

```

1. This won't make it shorter in your case, but `Self` is a keyword that is the type of the current struct. So, you could also write

```rust
    fn die_now(&self) -> Self {
        return Self { is_dead: true };
    }

```

Now let's look at some small differences between the your rust and your Kotlin code:

1. In Rust, but not in Kotlin you have to write

```rust
    fn new() -> Cat {
        Cat { life: Life::new() }
    }

```

maybe there is some macro to `#[derive(..)]` this. 2. In Rust, but not in Kotlin, you have to write `impl Life`. This is longer, but has the advantage that you can define methods at multiple different places, as long as it's in the same crate (doesn't have to be in the same module or file. Maybe there is some macro-syntax-sugar for this. My advice: Don't use macro-syntax-sugar it's a recipe for desaster. 3. I like the syntax of `println("cat is alive? ${cat.isAlive()}")`. I whish rust had that. 4. In the Kotlin code it is less clearly to see that `override fun fit` belongs to the `Fittable` interface and not to the `Yelled` interface.

There is another difference. One that isn't some superficial syntax-difference, but an important, deeply engrained language design difference. In Kotlin (and e.g. C++) you can inherit methods. Like this

```rust
abstract class Life {
    ...
    fun dieNow() {
        this.isDead = true;
    }
}
class Cat: Life {
    ...
}

```

Now you can call `cat.dieNow()`, where as in Rust, you had to add

```rust
    fn die_now(&mut self) {
        self.life.die_now();
    }

```

Discussion the advantages and disadvantages of this (I think it's called method inheritance) is too big of a topic for a forum comment. (One disadvantage of method inheritance is that it often breaks the `Go To Definition` feature of many IDE's.) Maybe someone can link a blog post or talk or paper about this. One disadvantage of Rust here, is that if life had `n` methods and You had `m` animals, you would need `n*m` of those do-nothing-wrappers. This is difficult to avoid. Possible ways are

1. As Steffahn has noted, Macros. They can make your code shorter, but they can also make you code horrible unreadable. Steffahn pointed out the existance of ambassador.
2. As Steffahn has noted, Replace `cat.die_now()` with `cat.life.die_now()`.
3. This way you only need `n+m` instead of `n*m` do-nothing-wrappers.

```rust
trait Animal {
    fn get_life(&mut self) -> &mut Life;
}
impl Animal for Cat {
    fn get_life(&mut self) -> &mut Life {
        &mut self.life
    }
}
impl Animal for Dog {
    fn get_life(&mut self) -> &mut Life {
        &mut self.life
    }
}
fn die_now<T: Animal>(x: &mut T) {
    x.get_life().die_now();
}

```

Also, while traits are rusts equivalent of inheritance or interfaces in other languages, you should use traits in Rust less often than inheritance and interface in other languages. You should try to write different style of code in different languages. For example, I wrote a lot of code that looks like this:

```rust
struct Animal {
    species: Species,
    // properties that all animals have go here
    is_dead: bool,
    is_male: bool,
    age: i32,
}
enum Species {
    Bird(Bird),
    Dog(Dog),
}
struct Bird {
    // properties that only birds have go here
    wingspan: f64,
}
struct Dog {
    // properties that only dogs have go here
    name: String,
}
impl Animal {
    fn is_alive(&self) -> bool {
        !self.is_dead
    }
    fn yell(&self) {
        if self.is_alive() {
            match self.species {
                Species::Bird(_) => println!("*bird noises*"),
                Species::Dog(ref dog) => println!("woof, my name is {}", dog.name),
            }
        } else {
            println!("Dead animals are silent");
        }
    }
    fn die_now(&mut self) {
        self.is_dead = true;
    }
}
fn main() {
    let mut dog = Animal {
        species: Species::Dog(Dog { name: "rex".into() }),
        is_dead: false,
        is_male: true,
        age: 5,
    };
    println!("dog is alive? {}", dog.is_alive());
    dog.yell();
    dog.die_now();
    dog.yell();
}

```

This has many advantages and disadvantages. One disadvantage is that you have to list all Animals in _one_ enum. You cannot define a third animal type in a different crate.

(I have no idea why I took the time to write this, I need to stop wasting my time writing stuff like this in forums and get back to work.)

---

<div class="post-metadata">

**Author:** ![Volker\_Weissmann](https://avatars.discourse-cdn.com/v4/letter/v/c2a13f/32.png) [@Volker\_Weissmann](https://internals.rust-lang.org/u/Volker_Weissmann)\
**Post date:** [September 9, 2021, 4:00pm UTC](https://internals.rust-lang.org/t/writing-code-with-rust-cost-so-many-lines/15304/5 "2021-09-09T16:00:56Z")

</div>

Thanks for pointing out ambassador's existance. I did not know that.

---

<div class="post-metadata">

**Author:** ![mbrubeck](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mbrubeck/32/174_2.png) [@mbrubeck](https://internals.rust-lang.org/u/mbrubeck)\
**Post date:** [September 9, 2021, 4:10pm UTC](https://internals.rust-lang.org/t/writing-code-with-rust-cost-so-many-lines/15304/6 "2021-09-09T16:10:53Z")

</div>



---

<div class="post-metadata">

**Author:** ![mbrubeck](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mbrubeck/32/174_2.png) [@mbrubeck](https://internals.rust-lang.org/u/mbrubeck)\
**Post date:** [September 9, 2021, 4:12pm UTC](https://internals.rust-lang.org/t/writing-code-with-rust-cost-so-many-lines/15304/7 "2021-09-09T16:12:12Z")

</div>

Feel free to discuss this further on the Users forum.
