Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create macro for creating kwargs dict? #1463

Open
birkenfeld opened this issue Mar 3, 2021 · 6 comments
Open

Create macro for creating kwargs dict? #1463

birkenfeld opened this issue Mar 3, 2021 · 6 comments

Comments

@birkenfeld
Copy link
Member

While calling methods with only positional arguments of different types is pretty easy (with tuples of IntoPy), for kwargs it gets complicated (see #1462).

Would it be useful to have a macro that can be used like so:

obj.call((pos_arg1, pos_arg2), kwargs! { key1=value1, key2=value2 })
@davidhewitt
Copy link
Member

davidhewitt commented Mar 3, 2021

Absolutely! I've thought about this before and I think we can do one better and support python collections a-la vec! and maplit::hashmap! etc. I think I'd make them look like this:

py_list!(py, [a, b, c]);
py_tuple!(py, (a, b, c));
py_dict!(py, {a => 1, b => 2, c => 3});  // or {a: 1, b: 2, c: 3} for if that's technically possible, maplit says it's not
py_set!(py, {a, b, c});
py_frozenset!(py, {a, b, c});

I think these have more general use than a kwargs! macro.

Also when we add functionality to use vectorcall to call Python functions, then I think we might need some kind of py_call! macro which does the magic.

@daniil-konovalenko
Copy link
Contributor

daniil-konovalenko commented Mar 3, 2021

I wonder if we can take the Python instance from the scope implicitly:

list![a, b, c];
tuple!(a, b, c);
dict!{a => 1, b => 2, c => 3};
set!{a, b, c};
frozenset!{a, b, c};

so that

Python::with_gil(|py| {
    let my_list = list![1, 2, 3]
});

would expand to something like

Python::with_gil(|py| {
    let my_list = PyList::empty().unwrap();
    my_list.append(py, 1).unwrap();
    my_list.append(py, 2).unwrap();
    my_list.append(py, 3).unwrap();
});

I think it would look more familiar to Python users. I'm not sure though that being implicit here is a good idea. Also it relies heavily on the convention to name the Python instance py, which is brittle.

@birkenfeld
Copy link
Member Author

And it doesn't even work (with macro_rules macros) since you can't use outer identifiers in the expansion without passing them in. That shows that Rust doesn't want us to do this in the first place :)

@daniil-konovalenko
Copy link
Contributor

Ah, right, thanks. Never mind then :)

@davidhewitt
Copy link
Member

davidhewitt commented Mar 14, 2021

Reminder for myself: I was thinking it might be nice if we can also use spread syntax in these macros.

e.g.

let left = py_list!(py, [a, b]);
let right = py_list!(py, [c, d]);
let joined = py_list!(py, [*left, *right]);

@mejrs
Copy link
Member

mejrs commented May 11, 2021

let joined = py_list!(py, [*left, *right]);

I'm not a fan of this (nor =>), That we can cook up whatever syntax we want doesn't mean we should. * already means something else in Rust, and it won't be obvious to people that are not familiar with Python. => similarly means something else in Rust and isn't used in Python at all (?).

kwargs! { key1=value1, key2=value2 }

I do like this syntax.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants