Skip to content

NEP: Add NEP-35 instructions on reading like= downstream #17725

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

Merged
merged 3 commits into from
Nov 16, 2020

Conversation

pentschev
Copy link
Contributor

This PR is a follow-up to a discussion in #17678 where I was attempting to pass like= downstream when that keyword is available on the implementation. However, thanks to @hameerabbasi pointing this out, we have a much cleaner solution from NumPy's perspective, where no changes are necessary to code. Everything can be done directly within the downstream implementation, and the changes here are only reference instructions on doing that.

@pentschev
Copy link
Contributor Author

cc @hameerabbasi @seberg @eric-wieser @shoyer @rgommers @quasiben @jakirkham @mrocklin @leofang

Also @jni @ilayn @mattip @Qiyu8 as you have provided feedback on the previous update to this NEP in #17093 , but don't feel obligated to do so again. :)

# If ``like`` is contained in ``da_func``'s signature, add ``like=self``
# to the kwargs dictionary.
if 'like' in kwonlyargs:
kwargs['like'] = self
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seeing the dance with getfullargspec (which obviously could be replaced with something else though), I actually wonder if the always pass solution (forcing downstream to drop it if they do not want to add like= to their own wrapper) isn't the better solution after all? Maybe we really need some opinions how downstream authors feel about being forced to drop the kwarg, @hameerabbasi is one of them, @shoyer, or @mhvk may also have opinions?

The issue is whether like=arrlike is passed as a kwarg to __array_function__ or (as currently the case) dropped and access to arrlike would have to be achieved by falling back to self.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seeing the dance with getfullargspec (which obviously could be replaced with something else though), I actually wonder if the always pass solution (forcing downstream to drop it if they do not want to add like= to their own wrapper) isn't the better solution after all? Maybe we really need some opinions how downstream authors feel about being forced to drop the kwarg, @hameerabbasi is one of them, @shoyer, or @mhvk may also have opinions?

FWIW, I would rather not force downstream libraries to drop like manually. The solution here is, IMO, much more convenient for the majority of libraries (e.g., CuPy, that won't need like= explicit nor have to do any changes on their side), while still providing at least a couple of different alternatives to libraries that may have a use for like= (e.g., Dask). Take my opinion with a grain of salt, but I'm here trying to chime in as a maintainer for Dask's __array_function__, and potentially to CuPy as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@seberg - for astropy's Quantity, I think we could fairly easily deal with it either way, though having the like argument might be slightly more convenient with the current setup. But being an ndarray subclass, we're not really the target audience for the like argument anyway: in the end, we generally just wrap the numpy function call instead of calling something else entirely. I can definitely see that for dask/cupy it would be easier to just call their own routines, passing all the arguments (and since it is guaranteed that the argument of like is self, that should be OK; while arguably __array_function__ could have been a class method, I think we also use that it is not). That said, code simplicity does count!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I was just curious what you think. I don't mind this, and we could make it more convenient in the future by providing the list of these function (e.g. as a special attribute on the public symbol).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind having this list either, on the contrary, I think it would be useful. Would you prefer to have that still in 1.20 or should we leave it as is while this is experimental and, assuming we'll transition this feature to stable, try to address it in 1.21?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we consider adding it even now if it is useful to you. My gutfeeling would be making the example effectively: if getattr(public_api, "__array_function_like_is_self__", False): ... with some bike shedding on the name?

It doesn't really strike me as a difficult decision to be made. Although we could add a test in NumPy that such an attribute is set if inspect detects a like argument.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I just realized that tagging something on to a C-defined function may be a bit too involved...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, exactly. I think we can't inspect functions like np.array, but maybe there's some way I don't know of.

Copy link
Member

@seberg seberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Peter. The changes look good to me, and are mostly in the technical "appendix". With or without changes, I will plan to merge it in the next days.

I currently assume we will change the like= argument to be strict. I am not sure if that requires a real change here, but maybe we could include a snippet explaining that:

def asduckarray(arr):
    if hasattr(arr, "__array_function__"):
         return arr
    return np.asarray(arr)

is a solution for libraries who want to use this, but are currently stuck with the coercing behaviour of np.asarray.

np.asarray([1, 2, 3], like=da.array(cp.array(())))

# Returns a cupy.ndarray
type(np.asarray([1, 2, 3], like=da.array(cp.array(()))).compute())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be nice to paste the output so that the user can read up that the next sentence is true, but just a thought and a tiny one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about this, but all the code here is "copy-pasteable", thus I added the output as comments instead. Therefore, I'd rather not add the outputs risking making it more confusing.

# If ``like`` is contained in ``da_func``'s signature, add ``like=self``
# to the kwargs dictionary.
if 'like' in kwonlyargs:
kwargs['like'] = self
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I was just curious what you think. I don't mind this, and we could make it more convenient in the future by providing the list of these function (e.g. as a special attribute on the public symbol).

@pentschev
Copy link
Contributor Author

I currently assume we will change the like= argument to be strict. I am not sure if that requires a real change here, but maybe we could include a snippet explaining that:

def asduckarray(arr):
    if hasattr(arr, "__array_function__"):
         return arr
    return np.asarray(arr)

is a solution for libraries who want to use this, but are currently stuck with the coercing behaviour of np.asarray.

We could do that, but I'm also wondering if we shouldn't then just introduce NEP-30 and be complete instead of suggesting a downstream implementation, what do you think?

Co-authored-by: Sebastian Berg <sebastian@sipsolutions.net>
@seberg
Copy link
Member

seberg commented Nov 13, 2020

That is true, we could add np.asduckarray (although that proposal goes a bit further, since it has its own dunder, which means it could be implemented for objects that do not implement __array_function__, i.e. a coercion). It was just a thought, I am not sure I feel like pushing for NEP-30 for this release, considering that a 3 liner exists to achieve much the same.

@pentschev
Copy link
Contributor Author

That is true, we could add np.asduckarray (although that proposal goes a bit further, since it has its own dunder, which means it could be implemented for objects that do not implement __array_function__, i.e. a coercion). It was just a thought, I am not sure I feel like pushing for NEP-30 for this release, considering that a 3 liner exists to achieve much the same.

I'm ok with delaying that too, it was just a thought on trying to get everything done in one go.

@seberg seberg merged commit 5da4a8e into numpy:master Nov 16, 2020
@seberg
Copy link
Member

seberg commented Nov 16, 2020

Well, putting this, we can always fix it up. If duckarray was important to you, I would consider it, but if it is not... Lets focus on the strict like argument first.

@pentschev pentschev deleted the nep-35-downstream-like-instructions branch February 23, 2021 11:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants