How to match trait bounds in a macro? - macros

I'm trying to match the trait bounds for generic types:
macro_rules! test {
(
where $(
$bounded_type:ident: $( $bound:tt )++,
)+
) => {
// Dummy expansion for test:
struct Foo<T, U>
where $(
$bounded_type : $( $bound )++,
)+
{
t: T,
u: U
}
}
}
test! {
where
T: PartialEq + Clone,
U: PartialEq,
}
fn main() {}
Unfortunately, if I understand well, the only way to match a trait is a tt fragment, but this fragment can match almost anything, so whatever I do, I get an error:
error: local ambiguity: multiple parsing options: built-in NTs tt ('bound') or 1 other option.
How can I match this piece of code?
Note that I do not need something very elegant (I do not need it for plublic users) but of course, the more elegant, the better.

Your best bet is to read the source code for the parse-generics-shim crate; it's a bit old, but should hopefully still work. This is way too convoluted to explain in a Stack Overflow question, since it would basically involve copy+pasting the source of that crate into the answer.
The easier approach is to just not parse actual Rust syntax, and use something the macro parser can handle, like wrapping the constraints in a group (like { ... }).

I was able to get this to match by splitting the first bound from the rest.
macro_rules! test {
(
where $(
$bounded_type:ident: $bound:tt $(+ $others:tt )*,
)+
) => {
// Dummy expansion for test:
struct Foo<T, U>
where $(
$bounded_type : $bound $(+ $others)*,
)+
{
t: T,
u: U
}
}
}
However, this isn't going to work if the traits have parameters.

Since around 2016 with the closing of this issue, you could use the path macro type to match TypePaths.
For example, from my own code:
($name:ident<$($l:lifetime, )*$($x:ident : $xt:path),+>($s:ident$(, $a:ident: $t:ty)*) -> $ret:ty => $body:block) => {
}

Related

Scala: Prepending an Underscore to Function Name

I have encountered an example where we have a function that takes a param and also defines some inner functions.Then we execute one of the functions based on what the value of this param is. All the inner function have an underscore prepended to the name. Is there some semantic significance to this "underscore style"?
def outsideFunction(param: SomeType) {
_inner1() = { ...}
_inner2() = {....}
param match {
case result: Int => _inner1()
case result: String => _inner2()
}
}
Is there some semantic significance to this "underscore style"?
No. I'd suspect someone who is used to a (far from universal, but not uncommon) Java convention of prefixing fields with _ to more easily distinguish them from local variables. As cdncat's comment says, this is a specific case of Hungarian notation.
At any rate, if the functions are really each used only once, I can't really think of any reason to prefer it over
def outsideFunction(param: SomeType) =
param match {
case result: Int => // body of _inner1
case result: String => // body of _inner2
}

Generics error: more specific type does not coform to more generic type

I have the following snippet of code:
private class SectionConversionMap
extends HashMap[SectionSchema[_], ( Iterable[HtmlRow] ) => Option[Iterable[_]]] {
private type Value[Vt] = ( Iterable[HtmlRow] ) => Option[Iterable[Vt]]
private type SuperKV = (SectionSchema[_], Value[_])
def +[T](kv: (SectionSchema[T], Value[T])):
HashMap[SectionSchema[_], ( Iterable[HtmlRow] ) => Option[Iterable[_]]] = {
super.+(kv: SuperKV)
}
def get[T](key: SectionSchema[T]): Option[Value[T]] = {
super.get(key) match {
case v: Some[Value[T]] => v
case _ => None
}
}
}
The issues is that my IDE says (in the + method's body, kv: SuperKV) that
Expression of type (SectionSchema[T], SectionConversionMap.this.Value[T]) does not conform to expected type (SectionSchema[_], SectionConversionMap.this.Value[_])
How is that possible? The second one is more generic.
The underscore isn't the equivalent of "?" in Java, although much of the time it can be used in the same way. "_" is for specifying higher-kinded types and that does seem to be, more or less, what you're trying to do here, though I think your code could do with some cleanup of the way types are defined.
Nevertheless, you can make your code compile with the simple expedient of replacing HashMap with Map. Was this an oversight on your part? I can't see any reason why you would want to try to extend HashMap instead of Map (my compiler actually gives a warning about that too).

Rust: Is there a way to call a static function on a macro type argument?

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.

How do I use parameter overloading or optional parameters in rust?

I am trying to write a print function for a binary tree and here is what I have so far:
impl TreeNode {
fn print(&self) {
self.print(0);
}
fn print(&self, level: u8) {
for _i in range(0,level) {
print!("\t");
}
match self.data {
Some(x) => println!("{}",x),
None => ()
};
match self.left {
Some(ref x) => x.print(level+1),
None => ()
};
match self.right {
Some(ref x) => x.print(level+1),
None => ()
};
}
}
I am getting the error: duplicate definition of value print. So I was wondering if there is a way to create functions with the same name but different arguments. Alternatively optional parameters would solve this problem, but I don't think that is possible at the moment (at least I couldn't find it via a Google search).
So, what is the best way to do this? Renaming the second print function works but looks ugly and requires you to remember more than one function name if I want to (for this example) print starting from the middle of the tree.
Rust does not have overloading, so it is impossible to have two functions or methods with the same name and with different sets of parameters.
However, it is sometimes possible to emulate overload with traits. This approach is likely inappropriate for your use case, but you can see how it is done in the standard library, where Path::new() constructor can be called with something resembling a vector of bytes:
Path::new("/a/b/c/d") // argument is &str
Path::new(b"/a/b/c/d") // argument is &[u8]
Path::new(Path::new("/a/b/c/d")) // argument is another Path
This is done via BytesContainer trait, and new() method is defined like this:
fn new<T: BytesContainer>(bytes: T) -> Path { ... }
Then this trait is implemented for all the types you want:
impl<'a> BytesContainer for &'a str { ... }
impl<'a> BytesContainer for &'a [u8] { ... }
impl BytesContainer for Path { ... }
// and more
This resembles overloading precisely because new() does exactly the same thing regardless of what kind of input it is provided; it is just a convenience thing which makes Path constructor more flexible. In the end new() just converts its argument to a byte slice. However, this does not allow you to have completely different functions with the same name.

Scala analogue to "with object do begin ... end" (shortcutting method access)

In old rusty Pascal there were convenient construct to perform a sequence of actions on object or record:
with obj do
begin
methodCall
otherMethodCall
...
end
I'm trying to touch something similar in scala, but something missing in my head :)
Is it possible to achieve somehow such effect, as if obj was in current scope of passed closure and behaved as this:
{
import obj._
callObjMethod(x, y)
objVal.doSomething()
...
}
But in customized syntax like:
doWith (obj) {
callObjMethod(x, y)
objVal.doSomething()
}
Intuitionally I feel that it's more no than yes but curiosity wants to know for sure.
Do you mean like this?
val file = new java.io.File(".")
// later as long as file is in scope
{
import file._
println(isDirectory)
println(getCanonicalPath())
}
You can just use the import keyword to bring the methods of the object in scope.
One possibility is the tap method:
def tap[A](obj: A)(actions: (A => _)*) = {
actions.foreach { _(obj) }
obj
}
tap(obj) (
_.callObjMethod(x, y),
_.objVal.doSomething()
)
or after using enrichment
implicit class RichAny[A](val obj: A) extends AnyVal {
def tap(actions: (A => _)*) = {
actions.foreach { _(obj) }
obj
}
}
obj.tap (
_.callObjMethod(x, y),
_.objVal.doSomething()
)
I think that with macros you should even be able to get your desired syntax (and avoid the overhead of creating the function objects), but I'll leave that to someone else.