-
Notifications
You must be signed in to change notification settings - Fork 306
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
Implement arithmetic ops on more combinations of types #744
base: master
Are you sure you want to change the base?
Conversation
In particular, this adds implementations for `ArrayView` where `&ArrayBase` was allowed previously, and it adds support for in-place operations where the RHS is any array (instead of requiring the RHS to be a reference).
I agree that it reduces verbosity and accidental complexity: you are not left puzzled trying to understand why only certain combinations are allowed. |
As the initiator of #743 I will say that I just straight-up missed the relevant documentation (and/or didn't properly grok it) and while adding this feature would have saved me a little time I wouldn't want you to trade nice code or fast compiles just to have it. Looking at the documentation now I can't figure what went wrong. Maybe I was thrown off by the use of |
The summary issue is #699 where we coordinate work on this - we definitely want to improve this in some way. I'd investigate what's the total count of arith ops impls before and after this change? What's the clean build time of the ndarray crate before and after? One suggested strategy for improving compilation time given in #699 is to have fewer impl blocks that cover more cases. We can use marker traits if needed. (We can use https://doc.rust-lang.org/nightly/std/array/trait.LengthAtMost32.html as inspiration in a way - it's a marker that allows each other array trait impl to be written as one I think this should be seen in context of #699. Here we add more impls that do the same "clone whole array and then do the op", which is something we want to fix. |
Treating ArrayView and &ArrayBase same seems sensible. So I'd say it would be great if those could be treated in the same impl. |
src/impl_ops.rs
Outdated
|
||
/// Perform elementwise | ||
/// between the scalar `self` and array `rhs`, | ||
/// and return the result as a new `Array`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not important, but just something I saw. Allegedly this doc is not visible in rustdoc, but that comment may be outdated now(!). then we want that #[doc=$doc]
back to make a complete sentence.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would especially discourage these impl blocks. We have to spend a lot of impl blocks on the arithmetic ops with scalars on the left hand side. Part of me want to just remove everything with left hand side scalars, because it can never(?) be properly general because of how we need to express it as an impl .. for $scalar
(for a specific single type).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've removed this impl block in the most recent commit because it's not necessary.
Part of me want to just remove everything with left hand side scalars, because it can never(?) be properly general because of how we need to express it as an
impl .. for $scalar
(for a specific single type).
I understand the objection, and AFAIK it will never be possible to write these impls for generic scalars even after re_rebalance_coherence. However, IMO supporting left-hand-side scalars is important, even if it's just f32
/f64
. I use these impls all the time in my code. They are especially important for non-commutative ops, where it's not straightforward to just move the scalar to the other side.
src/lib.rs
Outdated
/// - `@&A` which produces a new `Array` | ||
/// - `@B` which consumes `B`, updates it with the result, and returns it | ||
/// - `@&A` or `@V` which produces a new `Array` | ||
/// - `@O` which consumes `O`, updates it with the result, and returns it |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for updating this, even if it's a draft PR or whatever, it makes it easy to discuss changes 🙂
@bluss's comments made me realize that we don't actually need separate implementations for
This is really nice. The only issue is that it's a breaking change because the return type is always |
It's nice to express, but it risks cementing one of the things we want to fix - excessive cloning? I don't think it's right to change the return type of |
(Fwiw, there is a benchmark to compare the "excessive cloning vs not" and there isn't so much difference. The benchmarks are called add_2d_alloc_* and I'm not sure it gains so much. The "x.to_owned() + y" approach has one benefit of having simpler loops - a "memcpy" to copy, one binary operand loop to add in place; when we lose the extra cloning we have a ternary operand loop instead, to add x and y and store into z? But if both perform the same, maybe the latter should have the moral victory? And we can even lose the Clone bound, which I guess means we have to do it.) |
In particular, this adds implementations for
ArrayView
where&ArrayBase
was allowed previously, and it adds support for in-place operations where the RHS is any array (instead of requiring the RHS to be a reference).This functionality seems useful. It doesn't allow anything that wasn't previously possible by adding a
&
in front of a parameter, but removing the requirement of a&
reduces verbosity and may be more friendly to new users.Thoughts?
See also #237 and #743.