Wanted to understand the difference between undef and define a macro as 0. Thanks.
#define MACRO 0
defines the preprocessor token MACRO to be the literal 0
#undef MACRO
Removes the definition of the preprocessor token MACRO so that it's as if it never existed.
For example:
#define MACRO 0
#if defined ( MACRO )
// we get here
#endif
#if ( MACRO )
// we don't get here
#endif
#undef MACRO
#if defined ( MACRO )
// we don't get here
#endif
A macro defined as 0 is still defined.
#define VAL 0
#ifdef VAL
// VAL is defined so this part will be entered
printf("%d", VAL); // <- prints "0"
#endif
#undef VAL
#ifdef VAL
// Val is now undefined, this part will not be entered
#endif
The difference is that "undefined" isn't the same as "0" (depending on your usage).
Used in a boolean context, e.g. #if MY_MACRO, there is no difference (because undefined translated to false).
However, once you check for some macro to be defined, there's a difference:
// this macro is defined but empty.
// #ifdef MY_MACRO would evaluate to true/be included
// #if MY_MACRO would evaluate to false/not be included
// occurances would be deleted, e.g. 'something = MY_MACRO;' would be changed to 'something = ;'
#define MY_MACRO
// this macro is defined and set to 0.
// #ifdef MY_MACRO would evaluate to true/be included
// #if MY_MACRO would evaluate to false/not be included
// occurances would be replaced, e.g. 'something = MY_MACRO;' would be changed to 'something = 0;'
#define MY_MACRO 0
// this macro is undefined (after these lines)
// #ifdef MY_MACRO would evaluate to false/not be included
// #if MY_MACRO would evaluate to false/not be included
// occurances would remain unchanged (as the macro isn't defined anymore), e.g. 'something = MY_MACRO;' would be kept as 'something = MY_MACRO;'
#define MY_MACRO Hello!
#undef MY_MACRO
In general:
#define always assigns some value and makes the macro being defined; even if the new value is "empty".
#undef will always remove the macro definition making it undefined; occurances will no longer be replaced.
One of them defines a macro in such a way that in certain contexts, occurrences of the macro identifier will be replaced with 0 by the preprocessor. The other removes any definition of a macro such that if the identifier is found in the same contexts, it is not replaced with anything by the preprocessor, it is instead left as is.
For example, the preprocessor turns this:
#define MACRO 0
int main()
{
return MACRO;
}
into this:
int main()
{
return 0;
}
But, it will turn this:
#define MACRO 0
#undef MACRO
int main()
{
return MACRO;
}
into this:
int main()
{
return MACRO;
}
In the second example, the C compiler will encounter the identifer MACRO and probably throw an error that it is undeclared, and the compilation will likely fail.
in the first case the symbol will not be defined(#ifdef MACRO will not 'enter'), in the second case you have MACRO defined as '0'
Related
I am building a crate which has the feature foo. This crate has a macro bar! that does subtly different things based on whether foo is set.
I could duplicate the entire macro:
#[cfg(feature = "foo")]
macro_rules! bar {
// Lots of rules...
( A ) => {
B
}
}
#[cfg(not(feature = "foo"))]
macro_rules! bar {
// Lots of rules...
( A ) => {
C
}
}
That's a lot of error-prone duplication. Two approaches that don't work:
We can't move the cfg inside the macro, because then it will expand in the crate user's scope, which does not have feature foo appropriately set.
We can't use a #[doc(hidden)] #[macro_export] macro_rules! bar_priv_impl__ helper macro and use #[cfg] on the helper macro since Rust 1.30, because users can now request use mycrate::bar; to only import the bar! macro, giving errors about how bar_priv_impl__! is not defined.
Is there any way that's better than full macro duplication? It gets really bad if you have N features you're testing on, as you need 2n duplications.
since Rust 1.30 [...] because users can now [...] only import the bar! macro
Actually, this solution is only possible in Rust 1.30 because of the ability to import macros like normal. Remember that your macro can also have use statements!:
#[macro_export]
macro_rules! bar {
($val:expr) => {{
use $crate::__bar_foo;
__bar_foo!($val)
}}
}
#[cfg(feature = "foo")]
#[macro_export]
macro_rules! __bar_foo {
($val:expr) => ($val + 1)
}
#[cfg(not(feature = "foo"))]
#[macro_export]
macro_rules! __bar_foo {
($val:expr) => ($val - 1)
}
You can also fully-qualify your helper macro invocation:
#[macro_export]
macro_rules! bar {
($val:expr) => ($crate::__bar_foo!($val))
}
Since the following are equivalent:
-2
2.unary_-
and since parentheses are optional for methods with no arguments, shouldn't
2.unary_-()
also evaluate to -2 ? Instead, I get:
error: Int does not take parameters
The book I'm working through says that unary_- is a method, though this error seems to suggest it is a property of Int. Is this correct?
Proceeding from evan058's advice, I decided to run an experiement:
class Myint1(n:Int) {
def unary_-() = -n /* method definition has parentheses */
}
class Myint2(n: Int) {
def unary_- = -n /* no parentheses in definition */
}
val n1 = new Myint1(3)
val n2 = new Myint2(3)
n1.unary_- /* prints -3 */
n2.unary_- /* also gives -3 */
n1.unary_-() /* prints -3 */
n2.unary_-() /* throws error: Int does not take parameters */
So unary_- is a method, not a property. The reason for the behavior is that there is a difference between a method definition with parentheses and without. Note that, expectedly, -n1 and -n2 both result in -3.
I thought "hygiene" would prevent collisions between Xs defined within my macro m! but that turned out not to be the case. What am I misunderstanding?
macro_rules! m {
($e:expr) => {
const X: i32 = $e;
};
}
m!(0);
m!(1);
fn main() {
m!(2);
m!(3);
}
Playground
Error message:
error[E0428]: the name `X` is defined multiple times
--> src/main.rs:3:9
|
3 | const X: i32 = $e;
| ^^^^^^^^^^^^^^^^^^
| |
| `X` redefined here
| previous definition of the value `X` here
...
7 | m!(0);
| ------ in this macro invocation
|
= note: `X` must be defined only once in the value namespace of this module
From The Rust Programming Language (first edition)'s section on macro hygiene:
This [i.e. renaming] holds for let bindings and loop labels, but not for items
The Rust reference defines items:
An item is a component of a crate. Items are organized within a crate
by a nested set of modules. Every crate has a single "outermost"
anonymous module; all further items within the crate have paths within
the module tree of the crate.
Items are entirely determined at compile-time, generally remain fixed
during execution, and may reside in read-only memory.
There are several kinds of items:
modules
extern crate declarations
use declarations
function definitions
type definitions
struct definitions
enumeration definitions
union definitions
constant items
static items
trait definitions
implementations
extern blocks
This makes sense: if you you introduce an item in a macro you presumably want to actually use it from other items/modules/crates (and thus outside the macro), but you can't if you don't know its name, so the compiler can't rename it.
This code:
#![feature(macro_rules)]
macro_rules! new(
($my_type:ty) => ( $my_type::new() );
)
struct Foo {
blah: int
}
impl Foo {
fn new() -> Foo {
return Foo { blah: 0 }
}
}
fn main() {
let my_foo = new!(Foo);
println!("Foo's value: {}", my_foo.blah);
}
Looks good enough, but it fails with this error:
test.rs:4:25: 4:32 error: unexpected token: `Foo`
test.rs:4 ($my_type:ty) => ( $my_type::new() );
^~~~~~~
If I go into the macro and replace $my_type with Foo it compiles and runs just fine, so Foo is clearly valid in that position. Unless Foo comes from macro substitution, apparently.
If I run rustc test.rs --pretty expanded, it doesn't show me the expanded macro. It just gives me the same error message. I suspect this means it's generating the message before it expands the macro, but it might just be that it doesn't show me anything unless the compile succeeds. Though that would severely limit the usefulness of --pretty expanded.
Based on other experiments, I can use the macro type arguments in basically every other place one would expect a type to work. You just can't call static functions on them. This seems like a rather arbitrary restriction, and the error message is certainly not helpful.
Why does this restriction exist? And is there a way around it?
The Foo::bar() syntax is creating the path Foo::bar and then calling that function, and only works with valid paths, it doesn't work with arbitrary types, e.g. (u8, i8)::bar() doesn't work. You can use the ident macro non-terminal, which takes a single identifier and can be used whereever an identifier is valid, including inside a path
#![feature(macro_rules)]
macro_rules! new(
($my_type: ident) => ( $my_type::new() );
)
struct Foo {
blah: int
}
impl Foo {
fn new() -> Foo {
return Foo { blah: 0 }
}
}
fn main() {
let my_foo = new!(Foo);
println!("Foo's value: {}", my_foo.blah);
}
UFCS offers calling such methods on arbitrary types, via the syntax <Type>::new() and so, when that is implemented, replacing your current macro with
macro_rules! new(
($my_type: ty) => ( <$my_type>::new() );
)
should work too.
I am a beginning practitioner in Scala and I saw a few different syntax for calling a method. Some are nice, as ignoring parenthesis for a parameterless method, or ignoring the dot as in
1 to 10
but some really puzzle me. for instance:
breakable { ... }
this is simply a method call right? Can I also do that for more than one parameter or a parameter which is not a parameterless function?
Thanks
There are two standard ways of calling methods:
obj.method(params) // dot notation
obj method (params) // operator notation
The above can be modified in the following ways:
If params is a single parameter, you can replace () with {}.
If params is a single parameter and you are using operator notation, you can drop the parenthesis.
If method doesn't take parameters, you can drop (params) (that is, drop the empty ()).
If method ends with :, then it actually binds to the right in operator notation. That is, (params) method_: obj is equivalent to obj.method_:(params).
Either way, spaces are optional as long as identifiers can be told apart. So one can add spaces to the dot notation, like obj . method ( params ) or write .method(params) on the next line -- as often happens with call chaining --, as well as remove spaces from the operator notation, as in a+b.
There's also some stuff with tuple inference, but I try to avoid it, so I'm not sure of the exact rules.
None of these will explain the example you are confused about, however. Before I explain it, however, I'd like to show some syntactic sugars that can also be used to call methods:
obj(params) // equivalent to obj.apply(params)
obj.x = y // equivalent to obj.x_=(y), if obj.x also exists
obj(x) = y // equivalent to obj.update(x, y)
obj op= y // equivalent to obj = obj op y, if op is symbolic
~obj // equivalent to obj.unary_~; also for !, + and -, but no other symbol
Ok, now to the example you gave. One can import members of stable values. Java can do it for static methods with its static import, but Scala has a more general mechanism: importing from packages, objects or common instances is no different: it brings both type members and value members. Methods fall in the latter category.
So, imagine you have val a = 2, and you do import a._. That will bring into scope all of Int methods, so you can call them directly. You can't do +(2), because that would be interpreted as a call to unary_+, but you could call *(4), for example:
scala> val a = 2
a: Int = 2
scala> import a._
import a._
scala> *(4)
res16: Int = 8
Now, here's the rule. You can call
method(params)
If:
method was imported into scope.
You keep the parenthesis (even if there's only one parameter)
Note that there's a precedence issue as well. If you write obj method(params), Scala will presume method belongs to obj, even if it was imported into scope.
If we desugar this we will have:
breakable({ ... })
this matches signature
breakable: (op: ⇒ Unit): Unit
and uses so named call-by-name arguments (you may think of this as pass a block of code as argument)
More over scala allows you to write this:
scala> def foo (op1: => Unit)(op2: => Unit) = {op1;op2;}
foo: (op1: => Unit)(op2: => Unit)Unit
scala> foo { println(1) } { println(2) }
1
2
Above is the example of curried function