Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Guide: explain why things like println! and vec! are macros in Rust #17190

Closed
kud1ing opened this issue Sep 12, 2014 · 15 comments · Fixed by #17717
Closed

Guide: explain why things like println! and vec! are macros in Rust #17190

kud1ing opened this issue Sep 12, 2014 · 15 comments · Fixed by #17717

Comments

@kud1ing
Copy link

kud1ing commented Sep 12, 2014

Many C/C++-people will wonder why in Rust macros are used for such simple tasks as printing and building a vector, while macros in C/C++ are mostly used for complex/advanced stuff.

Something like in Rust this is a macro because ... or you could use the following Rust functions directly, but calling the macro is easier because ...

@thestinger
Copy link
Contributor

In C++, container initialization looks like std::vector<int> {1, 2, 3, 4, 5} or std::map<std::string, int> {{"foo", 3}, {"bar", 5}} where the brace enclosed elements are a std::initializer_list<T> likely represented as (ptr, len). Rust does have slices, but lacks a way to move from them. In theory, &move T (a linear type - it must be moved from) could exist and &move [T] would cover this use case well.

It's very ugly to have a special cased macro for a type like Vec<T>, and I don't think it's possible to explain why it is that way beyond admitting that C++ handles this better and Rust may provide a better way of doing it in the future. In C though, people do use macros for basic stuff like emulating generics. GLib is one example of a library making extensive use of macros like this.

String formatting has to use macros because Rust doesn't have CTFE and variadic generics. Rust doesn't have comparable metaprogramming capabilities to C++ and D at a type system level.

Macros are used to work around language limitations, and although Rust's macros are less ugly and less crippled (explicit at the call site, hygienic, pattern matching on tokens or fully procedural) it isn't a good thing that the language needs macros for things like this.

@steveklabnik
Copy link
Member

Yes, I feel like this goes better in the (eventually redone) macro guide than in the Guide.

@kud1ing
Copy link
Author

kud1ing commented Sep 12, 2014

@steveklabnik: That's a good place for a more detailed explanation, but since most people will first read the guide, they will have these questions in the back of their minds. I think it would be good to at least point to the Macro guide.

@steveklabnik
Copy link
Member

The Guide cannot and should not explain all details.

@kud1ing
Copy link
Author

kud1ing commented Sep 12, 2014

Of course not. I mean something like We'll see in the Macros guide, why this is a macro in Rust

@liigo
Copy link
Contributor

liigo commented Sep 13, 2014

Yes, println! appears in almost every Hello-World program of Rust, but it's not a function, and not imported (as a function). Many newbies will ask why. This should be covered in the guide, which do include a hello-world. Note: C has the very similar printf() function.

steveklabnik added a commit to steveklabnik/rust that referenced this issue Oct 2, 2014
@oconnor663
Copy link
Contributor

Since this issue is high in the Google results for this question, could someone give a brief explanation of why println! is a macro? :)

@tshepang
Copy link
Member

It's mentioned that it will be discussed later on in the (advanced) section, but a link to that section would help.

@thestinger
Copy link
Contributor

@oconnor663: Rust doesn't have compile-time function execution and variadic generics so it can't do the compile-time format string checking and code expansion without it. Macros are used to work around missing features, and in cases where they are very commonly used it would be better to improve the underlying language.

@oconnor663
Copy link
Contributor

@thestinger awesome, thanks.

@duesee
Copy link

duesee commented Feb 11, 2016

I know that this issue is over a year old, but since it's ranked quite high in Google, I felt like adding some different opinion can be helpful.

From my point of view: Macros in Rust are not just intended to "work around missing features" -- they are pretty clever.

Short: Rust-macros are expanded at compile time: print!("{} {}", 1, 2) becomes print(1); print(2); (very simplified).

I suggest invoking rustc -Z unstable-options --pretty=expanded on any Hello World program or have a quick look here https://stackoverflow.com/questions/28580386/how-do-i-see-the-expanded-macro-code-thats-causing-my-compile-error.

As far as I have seen, they are also used to introduce new features and shorthands on the syntax level.

For me this seems like an elegant solution... How do other languages manage this?

@sanmai-NL
Copy link

@duesee: I don't see it as elegant in the case of print!, since it apparently translates to multiple function calls where one would do.

@liigo
Copy link
Contributor

liigo commented Jun 21, 2016

@steveklabnik commented on 12 Sep 2014
The Guide cannot and should not explain all details.

Yeah, after a delay of almost two years, he eventually did something (#17717):

Rust implements println! as a macro rather than a function for good reasons, but that's a very advanced topic. You'll learn more when we talk about macros later.

... but that pr didn't answer this issue's question -- Why println! was implemented as a macro (instead a function)? -- (so this issue should keep open?) (and i don't think macro is a 'very advanced' topic.)

Now I (Liigo, a rust newbie) will try to answer:

Rust doesn't has builtin variadic function support currently, so println! (or vec! etc.) can't be implemented as a function. We do have variadic macro, so it's a macro. (On one hand, It was considered that has variadic function support will make the language more complex. On the other hand, variadic macro can be implemented out of language, in std.)

Feel free to correct me if I'm wrong. Thanks!

Edit: no two years delay.
Edit2: didn't get official answered for almost two years. If we can't put an answer into the book, maybe put it into FAQ?
Edit3:

@sanmai-NL
Copy link

sanmai-NL commented Jun 21, 2016

@liigo: from my perspective you expressed the above comments a bit harshly. For example, ‘eventually did something’ will perhaps come across as if the author was just being lazy here. I'll of course assume you didn't mean to leave such a criticism since @steveklabnik has been doing a lot. 👍

About the heart of your comment though: I see your point, I totally feel what you're getting at. The remark about macros that @steveklabnik made there leaves me, you and I guess many enthusiastic readers rather unsatisfied.

I like the simplicity of your rephrasing, especially the unparenthesized part (the first two sentences). One note: your English grammar wasn't fully correct yet.

I think the basic improvement suggestion for @steveklabnik and other documentation authors would be: don't write something is just too advanced or will be addressed elsewhere without elaboration.

@liigo
Copy link
Contributor

liigo commented Jun 22, 2016

@sanmai-NL I'm sorry for that! Updated.

lnicola pushed a commit to lnicola/rust that referenced this issue May 19, 2024
…_rpit, r=Veykril

Fix: Lifetime's Bound Var Debrujin Index in Dyn Traits

Surely fixes rust-lang#17182

I have tried running the analysis-stats in some of the repos mentioned in rust-lang#17080. No panic in almost all of them.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants