Please help my poor bird talk, OOPS

Hi There,
I am not coming from C or C++ background but from awesome modern languages like Java/Kotlin/TypeScript world.
now I am looking to choose something between Go vs Rust, I read alot about performance and safety (static/gc less etc etc), but looks like my own performance and safety is now on the toss :sweat_smile: , looking some help from you to guide me. I honestly do not want to spend months and months learning and then start to building something, I also do not want to write 50 lines if I can achieve the same thing with just 5 lines of code, and So I decided I will just spend my only weekend to take a call, if I really belongs to this place or switch to Go for good.

Nevertheless, Here is the code.

fn main() {
    let myPoorBird = Bird();
    myPoorBird.talk()
}

impl Bird {
   fn talk(){
        println!("brid is talking");
    }
}

I did try below
pub fn talk() <-- making it public
let myPoorBird = Bird{}; <-- using {} instead of () to make instance;
let myPoorBird = new::Bird(); <-- using new keyword;

You needed two changes:

  • Actually define the Bird struct.
  • Add &self to the method. If you don't, you would call it using Bird::talk, and it wouldn't be tied to an instance of the type.
fn main() {
    let myPoorBird = Bird {};
    myPoorBird.talk();
}

struct Bird {}

impl Bird {
    fn talk(&self) {
        println!("brid is talking");
    }
}
3 Likes
fn main() {
    let animal = Bird::default();
    animal.talk();
}

#[derive(Default)]
struct Bird;

impl Bird {
   fn talk(&self){
        println!("brid is talking");
    }
}

Playground.

Changes:

  • Defined the Bird data type
  • Derived Default trait and used it in a constructor-like fashion
  • Made talk take a &self parameter to make it a method instead of being an associated function
    • Alternatively you could just call Bird::talk()

As an aside, new is not a keyword. We just have a convention to call methods for new when they function as a constructor. For example:

impl Bird {
    fn new() -> Bird {
        Bird {}
    }

    fn talk(&self) {
        println!("brid is talking");
    }
}

You can now call it:

fn main() {
    let myPoorBird = Bird::new();
    myPoorBird.talk();
}

You could call the new method anything you wanted, but the convention is to call it new.

This also highlights the difference between methods that do and don't take &self.

2 Likes

The above one worked with adding a magic struct, but this last one, didn't work, however I like the last one syntax more than magic boiler struct.

error[E0433]: failed to resolve: use of undeclared type Bird

You still need the struct definition in the last one.

fn main() {
    let myPoorBird = Bird::new();
    myPoorBird.talk();
}

struct Bird {}

impl Bird {
    fn new() -> Bird {
        Bird {}
    }

    fn talk(&self) {
        println!("brid is talking");
    }
}

The struct Bird {} syntax probably makes more sense if you add fields to the struct. For example:

fn main() {
    let myPoorBird = Bird::new("Ari");
    myPoorBird.talk();
}

struct Bird {
    name: String,
}

impl Bird {
    fn new(name: &str) -> Bird {
        Bird {
            name: name.to_string(),
        }
    }

    fn talk(&self) {
        println!("{} is talking", self.name);
    }
}
1 Like

Not sure what do you mean by "magic struct". Structs are the main kind of data in Rust (together with enums), they're not "magic".

You might want to read chapter 5 of the rust book

Using Structs to Structure Related Data - The Rust Programming Language

I know you said

But that isn't what that book is about. It just covers the most important basics of Rust, so it's quite useful to read through it eventually while learning Rust. Not necessarily right away, it you prefer a hands-on approach, but it's not a thing that would take "months" to get through.


You can also look at the pages about structs

Structures - Rust By Example

and methods

Methods - Rust By Example

in the "Rust by example" book

3 Likes

Calling it magic :grin: because, it's just there doing nothing, why do we need it if has no data, it's justing adding more lines of code to manage and maintain, it means more time to spend, more money and more bugs. Eventually everything has to compile to machine code.
I believe compiler can be more logical to handle such scenarios, and it can infer without having to write a struct.

I think logic should be given precedences or rules.

I would surely read those links, because trials and error wouldn't going to work for Rust, since it's far different then modern languages.

I am just trying to relate if.

Impl == classes in java

Trait == interface ( and optional)

What is struct doing here, can't impl hold the data too?

impl in rust is the method part of a class in java. struct and enum are the data part of a class. You can have multiple impl blocks for the same type. In java only of a class methods can access private fields of a class. In rust every function or method in the same module as a type can access private fields of said type. Methods in rust are nothing more than syntax sugar for standalone functions. In java a class is a combination of data and behavior, while in rust a type is only data and behavior is handled independently separating data and behavior. This has several advantages like allowing to implement traits for types declared by dependencies or users of your crate.

1 Like

In the real world, the vast majority of structs have data in them. If you were allowed to not include the struct Bird {} for the case where there is no data in it, that's a pretty niche special case. It's better to not have that kind of special case for such a rare situation.

In many other languages, the list of fields and the list of functions is written together, but in Rust they are separate. The struct block defines the list of fields and the impl block defines the list of functions/methods. So a class in Java corresponds to both the struct and impl block together.

No, impl has only methods.

2 Likes

If you don't need the struct, then, well, you don't have to use impl blocks. Just implement everything with free functions.

2 Likes

I don't follow you there.

In Java everything is a class. If you want to represent a thing, like a bird, you create a class that holds the data representing the thing and the methods you can operate on the thing with. In Java everything has to be an object of some class.

Similarly Javascript(Typescript) and C++ have "class" to create such things. Although luckily there putting everything into a class is not compulsory.

In C++ one can also use struct as well as class. They are the same except all data and methods in structs are publicly accessible, unlike class.

What about Rust? In Rust things are represented by structs which hold any data pertinent to the thing. What would be class methods in other languages are added to the thing by putting them in an impl block for the struct.

So, at the level of your Bird example there is not much difference between Java/C++/Javascript style classes and Rust structs.

Of course if you don't ever want to have more than one bird one could just not use struct at all and simply have free functions. As you might in C/C++/Javascript.

I agree, do not add code to your programs that does nothing useful. Don't need a struct, then don't define one.

Your example then boils down to:

fn my_poor_bird_talk ()
    println!("brid is talking");
}

fn main () {
    my_poor_bird_talk();
}
2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.