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

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.

Related

How to match trait bounds in a macro?

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) => {
}

Bindings for functions with options parameter

It is common practice in JavaScript to have a function that takes in an options parameter, like so:
function foo({ bar1, bar2, bar3 }) {}
foo({ bar1: 5, bar2: 3 })
In Reason/OCaml, one would prefer to use labelled arguments for these functions:
let foo = (~bar1, ~bar2, ~bar) => {}
foo(~bar1=5, ~bar2=3, ())
Now, I know there is this way of creating Reason/Bucklescript bindings for functions like these:
type barObj;
[#bs.obj] external makeBarObj : (
~bar1: int=?,
~bar2: int=?,
~bar3: int=?,
unit
) => barObj = "";
external foo : barObj => t = "foo";
foo(makeBarObj(~bar1=5, ~bar2=3, ());
Is there, however, a simpler way of writing bindings for such functions? My problem with this approach is that it gets quite "long" when calling a function that takes in an options object, especially if it is a polymorphic argument, e.g.:
foo(`BarObj(makebarObj(~bar1=5, ~bar2=3, ())));
You can construct the object directly instead of using a separate function:
[#bs.val] external foo : Js.t({..}) => t = "";
let foo = (~bar1=?, ~bar2=?, ~bar3=?, unit) =>
foo({
"bar1": Js.Nullable.from_opt(bar1),
"bar2": Js.Nullable.from_opt(bar2),
"bar3": Js.Nullable.from_opt(bar3)
});
Which can be called with just
foo(~bar1=5, ~bar2=3, ());
But beware that this isn't exactly equivalent to what [#bs.obj] produces since properties being undefined are not always interpreted as not being defined.
If you need to pass it wrapped in a variant, you could have the object construction function wrap it. You can also usually define a set of functions instead:
fooWithString("bar");
fooWithOptions(~bar1=5, ~bar2=3, ());
Another hypothesis seems to be this one:
[#bs.obj]
external makeBarObj : (~bar1: string=?, ~bar2: int=?, ~bar3: string=?, unit) => barObj =
"";
[#bs.val] external foo : barObj => t = "foo";
let foo = (~bar1=?, ~bar2=?, ~bar3=?) => foo(makeBarObj(~bar1?, ~bar2?, ~bar3?, ()));
And then this way, the client of the API can simply call:
foo(~bar1=5, ~bar2=3, ())
It's basically the same thing as the solution presented in the question, but this hides the object conversion code in the library so that the client doesn't need to worry about it.

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 Returning a void function with 0 parameters, ugly syntax?

Given a method defined as follows
def descendEach(times:Int)(f:()=>Unit) {
for (i <- 1 to times) {
// other code
f()
}
}
when I use this method I want to be able to write
gd.descendEach(20){
println(gd.cost)
}
but the scala compiler only lets me get away with
gd.descendEach(20){ () =>
println(gd.cost)
}
which is kind of ugly. Am I missing something here? Is it possible to write it in the first way I presented?
Use the following syntax:
def descendEach[T](times:Int)(f: => T)
This way you can not only pass function without extra () => (this is called pass by name), but also use functions returning any type (not necessarily Unit). It is sometimes convenient when you have an existing function you want to pass but don't really care about its return value:
def g() = 42
descendEach(20)(g)
Note that with this syntax you are simply using f, not f().

How does Scala know what method to invoke ( named parameters )

class Algo {
def a( a : String = "Hola ", b : String = "adios" ) {
print( a )
print( b )
}
def a() {
print ("Uh?")
}
}
object Algo {
def main( args : Array[String] ) {
new Algo().a()
}
}
prints Uh?
If method a() is not defined, the code prints "Hola adios" using the default values.
So, I deduce, from this, that, if an exact signature is match, that is preffered.
Is this reasoning correct?
This behavior is clearly defined in SID #1, section 3.1.
Overloading Resolution In a method application expression, when multiple overloaded
alternatives are applicable, the alternative which use default arguments
is never selected.
Yes. Only if no fitting signature is found are default parameters used.
See this talk, some guy asks exactly for this.