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

Change PySet::new to accept a ExactSizeIterator #2789

Closed
samuelcolvin opened this issue Nov 29, 2022 · 7 comments · Fixed by #2795
Closed

Change PySet::new to accept a ExactSizeIterator #2789

samuelcolvin opened this issue Nov 29, 2022 · 7 comments · Fixed by #2795

Comments

@samuelcolvin
Copy link
Contributor

Somewhat related to #2673.

PyList::new has signature:

    pub fn new<T, U>(py: Python<'_>, elements: impl IntoIterator<Item = T, IntoIter = U>) -> &PyList
    where
        T: ToPyObject,
        U: ExactSizeIterator<Item = T>,
    {

But PySet::new is defined as

    pub fn new<'p, T: ToPyObject>(py: Python<'p>, elements: &[T]) -> PyResult<&'p PySet> {
        let list = elements.to_object(py);
        unsafe { py.from_owned_ptr_or_err(ffi::PySet_New(list.as_ptr())) }
    }

PySet::new elements parameter type should be relaxed to ExactSizeIterator<Item = T>, not a slice.

@adamreichold
Copy link
Member

Shouldn't it actually take IntoIterator<IntoIter=U> where U: ExactSizeIterator, i.e. exactly the same signature as PyList::new?

@mejrs
Copy link
Member

mejrs commented Nov 29, 2022

PyList requires ExactSizeIterator because it creates an empty list with a capacity (like vec::with_capacity). But PySet has no such api.

We can update PySet::new to just take an iterator and call PySet_Add in a loop.

@samuelcolvin
Copy link
Contributor Author

Shouldn't it actually take IntoIterator<IntoIter=U> where U: ExactSizeIterator, i.e. exactly the same signature as PyList::new?

agreed.

PyList requires ExactSizeIterator because it creates an empty list with a capacity (like vec::with_capacity). But PySet has no such api.

We can update PySet::new to just take an iterator and call PySet_Add in a loop.

Not sure what would be fastest, but currently PySet::new is creating an intermediate PyList, hence the matching signature would make sense.

@davidhewitt
Copy link
Member

davidhewitt commented Dec 3, 2022

My gut feeling is that using PySet_Add will be faster, because PySet_New is doing the iteration via Python dynamic protocol and also then we avoid the intermediate Python list allocation.

@samuelcolvin
Copy link
Contributor Author

Then I guess there should be a from_list for the specific case where you already have a list?

@mejrs
Copy link
Member

mejrs commented Dec 3, 2022

Then I guess there should be a from_list for the specific case where you already have a list?

If we let it take an IntoIterator, then users can just do PyList -> PyIterator -> PySet

@samuelcolvin
Copy link
Contributor Author

Awesome, thank you.

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

Successfully merging a pull request may close this issue.

4 participants