-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
RFC: Deprecate defaulting to scalar in broadcast #26212
Conversation
And then `collect()` all `Unknown` arguments before doing any real work.
Cool, this looks like an interesting change! On a technical level this looks good, and I can see it could be useful, but I have a few comments. Recently, I've been peddling a thought (e.g. here and here and elsewhere) which goes like "
I also happen to be in favor of strong, generic interfaces (i.e. generic interfaces that provide some guarantees on the behavior of their outputs) - for example we might say that Regarding Also, with this, for broadcasting with In conclusion - I'd just like to raise the question of whether we really want to tie the fallback behavior of |
I’ll also add that by working with |
Very good thoughts. A smattering of responses:
I don't find the distinction between iterable and indexable all that compelling. We privilege broadcast with the dot-syntax, and — while it'd be a PITA — its implementation could lean more heavily on iteration for key-less objects. Even without that implementation change, though, it's so very easy to support an indexing implementation with iterable arguments by collecting them first. I'd say that broadcasting is more about shapes than anything else… and we do have objects that are iterable and have shape but aren't indexable ( |
I would rather say "map is for iterables" and "broadcast is for things (iterables) with shapes"
I understand the desire for strong rules, but keep in mind that having those rules also limits what we can do. As an example currently a |
I think the proposed rule for map is that the order of the output vector should match the order of the iterator, but not necessarily that the output will be emitted in that order.
Perhaps Strings are simply a second example (like Matt's
I disagree. In the limit case of one item, being able to operate on each element in iteration order is useful |
So, for example, |
No, this is the current list of specially cased Scalar arguments: BroadcastStyle(::Type{<:Union{Number,Symbol,String,Type,Function,Uninitialized,RoundingMode,Nothing,Missing}}) = Scalar() The most dissatisfying ones are the singletons like |
You could always make singletons default to being treated as scalars and then opt-in to being a container for |
My point is simply that it's possible to make meaningful and useful things that are array-ish and definitely not scalar but still singletons. The whole idea here is to remove as many special cases as possible. Right now the rule is very simple: if a type doesn't define a |
I totally agree we should make a simple rule where user's don't need to consider special cases. For comparison, my proposal was: if a type doesn't define a Using this we gain over this approach that indices match up correctly by default + a good fallback implementation for As to what we should do for v1.0 - have we also considered just deprecating the Jameson wrote:
I do wonder whether this is precisely where it's a good think that |
I agree, I think we just have different solutions for this. I've taken the position that it should be possible to broadcast over an iterable, so it should be OK to drop indices if the user has expressed that they are optional (for example, by calling |
Closing in favor of #26435, which is based on that more radical proposal I linked to in the original post (remove |
This PR consists of two commits — both pass tests locally. The first commit changes the default behavior of broadcast to
collect
its arguments instead of treating them as scalars. The second layers on top a deprecation mechanism that makes this — largely — non-breaking.I believe this to be a compromise that will fix #18618 once deprecations are removed. Note that I kept all the types (except
Ptr
) that are currently tested to behave as scalars as being a part of theScalar
trait.I initially went even farther, and attempted to remove
Scalar()
from the broadcast machinery entirely. I like that it completely does away with the trait — you simply specializebroadcast_collect
to determine if you want to wrap your object in aRef
. It has the major downside, though, in that it'd make1 .+ 2 == fill(3, ())
. As a drastic alternative, we could consider unwrapping allAbstractArray{T,0}
s that result from broadcast and bringing them back into the scalar world.