Why is there no semicolon after a macro call? - syntax

I am following some tutorial I found on Rust, and I ran across something that my Java/C/C++ mind cannot comprehend:
impl fmt::Display for Matrix {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})\n({}, {})", self.0, self.1, self.2, self.3)
}
}
I don't understand the lack of semicolon at the end of the write! macro call. I get an error from the compiler if I add it.
I am guessing that if the semicolon is not there then the Result from write! is used as return value of fmt, but can anybody provide a more specific explanation to why that is and if it always applies?

The write macro uses the write_fmt() method either from std::fmt::Write or from std::io::Write; both return Result<(), Error> and you need to omit the semicolon in order to have it as the output of fmt().
from The Rust Book, 1st edition:
Rust functions return exactly one value, and you declare the type
after an ‘arrow’, which is a dash (-) followed by a greater-than sign
(>). The last line of a function determines what it returns. You’ll
note the lack of a semicolon here. If we added it in we would
get an error.
This reveals two interesting things about Rust: it is an
expression-based language, and semicolons are different from
semicolons in other ‘curly brace and semicolon’-based languages.

Related

How do I step into a function called in a return value when debugging with rust-gdb?

In the following code:
match fnA(size) {
Some(arr) => SomeBlock::new(size, &arr, false).as_ptr().add(1) as *mut c_void,
None => ptr::null::<c_void>() as *mut c_void,
}
I want to use rust-gdb to step into SomeBlock::new(size, &arr, false). When I run it normally, I am able to step into fnA, but if I try to step when I'm on the line with Some(arr), gdb just ends up running the rest of the program and exiting.
I know I can directly insert a breakpoint at SomeBlock::new, but I was curious if there was a cleaner way of doing it.
According to the GDB documentation on Rust:
The Rust expression evaluator does not support “statement-like” expressions such as if or match, or lambda expressions.
It seems that you cannot step into anything that is inside a match expression. Note that you can step into fnA as it is evaluated before its output gets matched inside the match block.

Eval expression during compilation time in Erlang

Is it possible to have some kind of constexpr equivalent in Erlang?
I have some expression
obj() -> func("some string")
in which func is a pure function (result does not depend on anything other than the arguments) and I would like it to be executed during compilation time. How can I achieve it?
EDIT I can accept any reasonable hacks, as long as they allow func to be a casual function
You could use ct_expand, part of Ulf Wiger's parse_trans repository. To use it, specify that the compiler should use ct_expand as a parse transform:
-compile({parse_transform, ct_expand}).
and then, for each expression you want to evaluate at compile time, wrap it in ct_expand:term/1:
obj() -> ct_expand:term(func("some string")).
See also the example module.
Erlang has things called macros, which are expanded at compilation time. Here's an example of what you can do:
a.erl:
-module(a).
-compile(export_all).
-define(FUNC(Str), "hello "++Str).
go() ->
?FUNC("world").
In the shell:
4> compile:file("a.erl", ['P']).
{ok,[]}
^C^C
At the command line:
~/erlang_programs$ cat a.p
-file("a.erl", 1).
-module(a).
-compile(export_all).
go() ->
"hello " ++ "world".

Matching borrowed enum - why is this syntax equivalent? [duplicate]

This question already has an answer here:
Why does pattern matching on &Option<T> yield something of type Some(&T)?
(1 answer)
Closed 3 years ago.
I have the following piece of code, which compiles using rustc v1.36:
enum Number {
Integer(i32),
Real(f32),
}
fn foo1(number: &mut Number) {
if let Number::Integer(n) = number {
let _y: &mut i32 = n;
}
}
fn foo2(number: &mut Number) {
if let &mut Number::Integer(ref mut n) = number {
let _y: &mut i32 = n;
}
}
Funny enough, I can understand how 'foo2' does the matching, but not so for 'foo1', while 'foo1' is the kind of code you will see in any Rust project. Can someone explain how the matching syntax in these 2 is equivalent? And thus it extend to other code (structures?) as well?
This functionality was added in Rust 1.26, and is called 'default binding modes' (or 'match ergonomics', after the RFC that proposed it). It effectively allows pattern matching to automatically dereference values, and to add ref and ref mut to variable bindings where needed.
The rules for this behaviour are discussed in detail in the RFC, but it effectively boils down to:
Variable bindings within a pattern can be resolved in one of three modes:
'move' (the default), which will move the value.
'ref', which will immutably reference the value.
'ref mut', which will mutably reference the value.
When a variable binding is encountered within a pattern without an explicit ref, mut or ref mut, the current binding mode will be used.
When a reference is pattern matched using a non-reference pattern:
The value will be auto-dereferenced.
The binding mode may change for any nested patterns:
If the type of the reference is &T, the binding mode will change to 'ref'.
If the type of the reference is &mut T and the current binding mode is not 'ref', the binding mode will change to 'ref mut'.
This may sound complicated, but as you can see from the end result, it tends to line up with how you'd intuitively write the match!

What does an # symbol mean in a Rust declarative macro?

I have seen the # symbol used in macros but I cannot find mention of it in the Rust Book or in any official documentation or blog posts. For example, in this Stack Overflow answer it is used like this:
macro_rules! instructions {
(enum $ename:ident {
$($vname:ident ( $($vty: ty),* )),*
}) => {
enum $ename {
$($vname ( $($vty),* )),*
}
impl $ename {
fn len(&self) -> usize {
match self {
$($ename::$vname(..) => instructions!(#count ($($vty),*))),*
}
}
}
};
(#count ()) => (0);
(#count ($a:ty)) => (1);
(#count ($a:ty, $b:ty)) => (2);
(#count ($a:ty, $b:ty, $c:ty)) => (3);
}
instructions! {
enum Instruction {
None(),
One(u8),
Two(u8, u8),
Three(u8, u8, u8)
}
}
fn main() {
println!("{}", Instruction::None().len());
println!("{}", Instruction::One(1).len());
println!("{}", Instruction::Two(1, 2).len());
println!("{}", Instruction::Three(1, 2, 3).len());
}
From the usage, it appears that it is used for declaring another macro that is local to the main one.
What does this symbol mean and why would you use it rather than just creating another top-level macro?
In the pattern-matching part of a macro, symbols can mean whatever the author desires them to mean. A leading symbol # is often used to denote an "implementation detail" of the macro — a part of the macro that an external user is not expected to use.
In this example, I used it to pattern-match the tuple parameters to get a count of the tuple parameters.
Outside of macros, the # symbol is used to match a pattern while also assigning a name to the entire pattern:
match age {
x # 0 => println!("0: {}", x),
y # 1 => println!("1: {}", y),
z => println!("{}", z),
}
With a bit of a stretch, this same logic can be applied to the use in the macro — we are pattern-matching the tuple, but also attaching a name to that specific pattern. I think I've even seen people use something even more parallel: (count # .... However, The Little Book of Rust Macros points out:
The reason for using # is that, as of Rust 1.2, the # token is not used in prefix position; as such, it cannot conflict with anything. Other symbols or unique prefixes may be used as desired, but use of # has started to become widespread, so using it may aid readers in understanding your code.
rather than just creating another top-level macro
Creating another macro is likely better practice, but only in modern Rust. Before recent changes to Rust that made it so you could import macros directly, having multiple macros could be tricky for end users who tried to selectively import macros.
See also:
Internal rules in The Little Book of Rust Macros
Why must I use macros only used by my dependencies
What does the '#' symbol do in Rust?
Appendix B: Operators and Symbols

Why does _ destroy at the end of statement?

I've seen a few other questions and answers stating that let _ = foo() destroys the result at the end of the statement rather than at scope exit, which is what let _a = foo() does.
I am unable to find any official description of this, nor any rationale for this syntax.
I'm interested in a few inter-twined things:
Is there even a mention of it in the official documentation?
What is the history behind this choice? Is it simply natural fall-out from Rust's binding / destructuring rules? Is it something inherited from another language? Or does it have some other origin?
Is there some use-case this syntax addresses that could not have been achieved using explicit scoping?
Is it simply natural fall-out from Rust's binding / destructuring rules?
Yes. You use _ to indicate that you don't care about a value in a pattern and that it should not be bound in the first place. If a value is never bound to a variable, there's nothing to hold on to the value, so it must be dropped.
All the Places Patterns Can Be Used:
match Arms
Conditional if let Expressions
while let Conditional Loops
for Loops
let Statements
Function Parameters
Is there even a mention of it in the official documentation?
Ignoring an Entire Value with _
Of note is that _ isn't a valid identifier, thus you can't use it as a name:
fn main() {
let _ = 42;
println!("{}", _);
}
error: expected expression, found reserved identifier `_`
--> src/main.rs:3:20
|
3 | println!("{}", _);
| ^ expected expression
achieved using explicit scoping
I suppose you could have gone this route and made expressions doing this just "hang around" until the scope was over, but I don't see any value to it:
let _ = vec![5];
vec![5]; // Equivalent
// Gotta wait for the scope to end to clean these up, or call `drop` explicitly
The only reason that you'd use let _ = foo() is when the function requires that you use its result, and you know that you don't need it. Otherwise, this:
let _ = foo();
is exactly the same as this:
foo();
For example, suppose foo has a signature like this:
fn foo() -> Result<String, ()>;
You will get a warning if you don't use the result, because Result has the #[must_use] attribute. Destructuring and ignoring the result immediately is a concise way of avoiding this warning in cases where you know it's ok, without introducing a new variable that lasts for the full scope.
If you didn't pattern match against the result then the value would be dropped as soon as the foo function returns. It seems reasonable that Rust would behave the same regardless of whether you explicitly said you don't want it or just didn't use it.

Resources