Why does macro hygiene not prevent collisions between multiple const definitions? - macros

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.

Related

How to use fresh identifier in function parameter list in Scala macro

In an effort to learn Scala's macro system, I thought I'd try my hand at writing a basic CPS transformation macro. I've already written a fairly comprehensive CPS transformation framework for Clojure, so I'm pretty familiar with the CPS transform itself. However, I'm getting stuck transforming function / method applications.
For the CPS transform, function calls of the following form:
cps(f(<a>, <b>, <c>, ...))
need to be translated into an expression of the form:
cps(<a>){ $a =>
cps(<b>){ $b =>
cps(<c>){ $c =>
... => f($a, $b, $c, ...)
}
}
}
Obviously, the parameters of the generated continuation lambdas (e.g., $a) need to be fresh symbols so they can't inadvertently conflict with variable names in the lexical context. So for each argument arg, I generate a fresh name:
val name = Ident(TermName(c.freshName))
(where c is the macro's Context) which I then use in the following quasiquote:
q"""cps(arg)($name => $remainder)"""
where remainder refers to the remainder of the computation.
The macro itself compiles fine, but when I try to use it with an expression that involves a function application, I get the following error:
... exception during macro expansion:
[error] java.lang.IllegalArgumentException: fresh$macro$1 is not valid representation of a parameter, consider reformatting it into q"val $name: $T = $default" shape
However, I don't think it's possible to perform the recommended "reformatting", since there is no $default to provide.
Here's a minimal example that illustrates the issue I'm having:
def id[A](expr : A) : A = macro idImpl[A]
def idImpl[A](c : blackbox.Context)(expr : c.Expr[A]) : c.Expr[A] = {
import c.universe._
val name = Ident(TermName(c.freshName))
//c.Expr(q"""val $name = $expr; $name""")
c.Expr(q"""($name => $name)($expr)""")
}
Note that it works if you replace the lambda expression with the commented line.
So my question: How can a name generated by freshName be used as the parameter name for an anonymous function?
I believe you need a ValDef of the form val $name: $T = _, where the _ is represented by NoTree. Initializing variables with _ is valid Scala, setting references to null and numbers to 0 (i.e. the default values), but is also used as an internal placeholder when there are ValDefs (e.g. function parameters) but no sane default.
I’m on mobile here, so I can’t test it. In any case, you can destructure the value q"a: Any => a" in the REPL to find what the compiler normally sets as the default, if NoTree doesn't work.

Is it possible to write a Rust macro "has_trait!(<type>,<ident>|<expr>)"?

I want to match, e.g. an ident's type to implement a certain trait, how would I do that?
Here the basic idea in (incomplete) code:
macro_rules! has_trait {
($ ($t : ty), ($x : ident),) => {
}
}
fn trait_test() {
let a = vec![1, 2, 3];
let b = 42;
let a_iteratable = has_trait!(IntoIterator, a);
let b_iteratable = has_trait!(IntoIterator, b);
println!("{:?} iterable? {}", a, a_iteratable);
println!("{:?} iterable? {}", b, b_iteratable);
}
I cannot wrap my head around how to say "any type which has trait Foo".
I see 2 options how to tackle the problem:
Find a match expression which matches any type with trait $t and simply return true on match, else (how works else?) false.
In the body of the match of any type, use some code to determine if trait $t is implemented by the type of $x.
I cannot see how to do either of both options.
Can this even be done?
I am afraid there is here a serious misconception about what macros can and cannot do.
In Rust, a macro acts on the AST, short for Abstract Syntax Tree. This means that it has access to syntactic information (only).
It means that anything that a macro does, you can also do without a macro. A macro is just syntactic sugar to avoid writing boilerplate over and over.
And conversely, if you cannot do something without a macro, you cannot do it with a macro either.
It is not immediately clear to me whether this information is available or not (proving a negative is always so difficult), however it is certain that the usage of macros has no influence on this availability.
As the other answers have already made clear, there is nothing a macro can do. And indeed, in current (stable) Rust, that's it. However, if you are willing to either use nightly or wait until specialization is stable, you can write and implement a trait to make that distinction, e.g.
#[feature(specialization)] // nightly only for now
trait HasMyTrait {
fn has_trait() -> bool;
}
impl<T> HasMyTrait for T {
default fn has_trait() -> bool { false }
}
impl<T: MyTrait> HasMyTrait for T {
fn has_trait() -> bool { true }
}
This is just a simple example, but you can switch out multiple implementations of whatever functionality you want based on if the type in question implements a trait or not.
This code requires Rust 1.11.0 nightly as of 2016-06-02 or newer.
What you basically want is static (or compile-time) reflection:
Assigning values at compile-time, depending on the type system, to use at run-time.
This is possible in for example D or even C++, but not in Rust.
Rust does not allow template specialisation or compile-time values as generic parameters, nor does it have static reflection capabilities like D.

Records with similar fields in OCaml

In this answer, the suggested way of "attaching" meta information to types was using a record:
type _foo = ...
and foo = {n:_foo; m:meta}
but what if I have multiple types I'd like to wrap with meta information? Apparently all field names in record types must have different names, and writing:
type _foo = ...
and foo = {n:_foo; m:meta}
...
type _fooX = ...
and fooX = {nX:_fooX; mX:meta}
seems redundant :/. Classes are the only way to solve this? I'd like to avoid dealing with classes, if possible.
You can use parameterized type, perhaps.
type 'a wrapped = { base: 'a; extra: meta }
Jeffrey's solution is correct and scales perfectly to recursive types.
type location
type 'a loc = { a : 'a; loc : location }
type exp = Int of int | Add of exp loc * exp loc
It is still possible to use the previous two-time definition of your type,
as follows:
type exp_data = Int of int | Add of exp * exp
and exp = exp_data loc
Finally, a slightly different style is to use "open recursion", that is to define only an "derecursified type" open_exp with free parameters instead of recursive occurences. You can then get the recursive type back by taking the fixpoint; you can take different fixpoint, one with no additional information, and one with location interleaved for example. This is a generic construction to insert information at recursion sites, and its term-level counterpart allows for weaving different things in a recursive function (memoization, profiling, debug, etc.).
type 'e open_exp = Int | Add of 'e * 'e
type simple_exp = Simple of simple_exp open_exp
type located_exp = Loc of located_exp loc open_exp

Implement equality outside type definition

I have several types that implement an interface. Equality for these types only depends on interface members. Is it possible to define equality for these types once, without overriding Equals or op_Equality for each type?
EDIT
I tried the following, but, for whatever reason, it overrode every use of =, even for types not implementing IEntity.
[<AutoOpen>]
module Equality =
let inline op_Equality (left:IEntity) (right:IEntity) = true
I also tried using flexible types (#IEntity). Same result.
What you're trying to do is something that mixins or typeclasses might enable in other languages; unfortunately there isn't equivalent functionality in F#. Your best bet is probably one of the following options:
Use an abstract base class instead of an interface.
Write your equality method outside of your type and then have all of your implementations defer to it. For example,
let entityEquals (i1:IEntity) (i2:IEntity) =
i1.Member1 = i2.Member1 &&
i1.Member2 = i2.Member2 &&
...
type MyEntity() =
interface IEntity with
member x.Member1 = ...
...
override x.Equals(y) =
match y with
| :? IEntity as y -> entityEquals x y
| _ -> false
override x.GetHashCode() =
...
In addition to a bit of boilerplate, the downside here is that if anyone else implements your IEntity interface, they aren't forced to use your equality method - it's opt-in.
Create an another operator which you use for equality testing of IEntitys:
let (==) (i1:IEntity) (i2:IEntity) =
i1.Member1 = i2.Member1 &&
...
The (huge) downside of this is that structural equality of types containing IEntitys (such as tuples, records, etc.) won't use this operator to compare those components, which is likely to lead to surprising broken code.
I don't think there is a way to do this in a static way. The problem is that extension members (e.g. if you added op_Equality as an extension) are ignored by static member constraints (e.g. if you also redefined = using inlin with op_Equality requirement).
The F# compiler has some special powers available only when compiling FSharp.Core.dll that could help (search sources for the declaration let inline GenericOne). It uses something like static type switch - but this cannot be accessed by mere mortals.
So, I don't have any idea better than using dynamic type test, which isn't really a good approach and it's probably better to define a custom operator for comparison of your interfaces.
For a reference, the ugly dynamic approach would be:
let inline (=) a b =
match a, b with
| :? IFoo as a, :? IFoo as b -> yourEquals a b
| _ -> a = b

OCaml types with different levels of specificity

I am attempting to simulate an interface in OCaml and am using the "type" construct. I have two types:
type fooSansBar = {a: string; b: int};;
type fooConBar = {a:string; b:int; bar:char};;
...and would like to define a particular fooSansBar:
let fsb = {a="a"; b=3};;
...but am told that the bar field is not defined. From this, it appears that, contrary to the values I passed in matching fooSansBar's signature, the system believes I am trying to create a fooConBar. Is it possible to create a fooSansBar if the two types as defined above exist?
Additionally (because I'm new to OCaml) is there a better way to simulate an interface?
In OCaml, field names in record types must be unique, so the two types you define cannot coexist simultaneously. Caml is the only language I know with this property.
Because the second definition hides the first, when the compiler sees the a and b fields it expects them to belong to the fooConBar type and so complains of the missing bar field.
If you are trying to simulate an interface, the correct functional way to do it in Caml is to define a module type.
module type FOO_CON_BAR = sig
val a : string
val b : int
val bar : char
end
And an instance:
module Example = struct
let a = "hello"
let b = 99
let c = '\n'
end
With modules and module types you also get subtyping; there's no need to resort to objects.
P.S. My Caml is rusty; syntax may be off.
There are several possible solutions in OCaml depending how you're using the code you gave. The simplest is to combine the two types:
type fooBar = { a: string; b: int; bar: char option }
Another solution is to replace the records with objects because objects support subtyping (and can have their types inferred so there is no need to declare a type!):
# let fsb = object
method a = "a"
method b = 3
end;;
val fsb : < a : string; b : int > = <obj>
# fsb#a, fsb#b;;
- : string * int = ("a", 3)
The second type redefines a and b, effectively hiding the first, which is why it cannot be constructed any more. You could define these types in different modules, but that would be the same as using a different name for a and b.
These constructs can only be used when you do not try to "derive" from another interface, but just implement it.
If you wish to use these object oriented concepts in Ocaml, you could look at the object system, or, depending on your problem, the module system. Alternatively, you could try to solve your problem in a functional way. What problem are you trying to solve?
OCaml provides two ways to implement interfaces. One, as already mentioned, is a module type.
The other is a class type. You can write a class type (interface) fooSansBar:
class type fooSansBar = object
method a: string
method b: int
end
and a class type fooConBar:
class type fooConBar = object
inherit fooSansBar
method bar: char
end
This will allow you to use a fooConBar anywhere a fooSansBar is required. You can now create a fooSansBar, using type inference:
let fsb = object
method a = "a"
method b = 3
end
Now, fsb's type happens to be <a: string; b: int>, as indicated by Jon, but it's perfectly usable as a fooSansBar due to OCaml's structural subtyping.
In OCaml, it's not possible to have two record types with intersecting field sets present in the same scope.
If you really need to use record types with intersecting field sets, then you can work around this restriction by enclosing the types within their own dedicated modules:
module FooSansBar = struct type t = {a:string; b:int} end
module FooConBar = struct type t = {a:string; b:int; bar:char} end
Then you can construct instances of these types like so:
let fsb = {FooSansBar.a="a"; b=3}
let fcb = {FooConBar.a="a"; b=4; bar='c'}
These instances have the following types:
fsb : FooSansBar.t
fcb : FooConBar.t