recent broadcast changes (iterate by default), scalar struct, and `@.`



I still think that should have been simply resolved as wontfix, despite the sensationalist issue title. For me, using broadcast with non-AbstractArray iterables is an extremely rare use case (honestly, not sure if I’ve ever done it). I’d gladly give that up to get the scalar-unless-AbstractArray behavior back.


I also think that “treat as scalar by default” is more sensible. If a user defines an iterator it makes sense for him to define broadcastable method for his type as part of the interface for an iterator. But under the current default user has to define broadcastable for his scalar struct. :confused:

If you read the discussion in issue 18618, the majority seems to be in favor of “treat as scalar by default” option, so it is surprising to me that the current “treat as iterator by default” option was chosen…

The strongest arguments in that discussion, IMO, were given by @stevengj and are as follows:

broadcast is for containers with shapes, and defaults to treating objects as scalars. map is for containers without shapes, and default to treating objects as iterators.

the whole point of broadcast is to be able to “broadcast” scalars to match containers, e.g. to do ["bug", "cow", "house"] .* "s" --> ["bugs", "cows", "houses"] . This is fundamentally different from the behavior of map.

I dislike any design that requires us to define a method for a type to be treated as a scalar. That should be the default.


It’s water under the bridge at this point, since the default can’t be changed in Julia 1.x without breaking compatibility. The current behavior wasn’t my first choice, but I can certainly live with it.


We can change the default in cases where it errors. Those are the cases you and others aren’t satisfied with.


Can this be done in a way that preserves the metasemantic construct underpinning Julia’s broadcasting?


For the record, this issue also affects @enum broadcasts, which might be a more common use than trying to broadcast across a singular struct.


Can you give minimum working example that demonstrates this?

@enum Foo foo1 foo2
b = Vector{Foo}(undef, 2)
b .= foo1

# Error!

Broadcast.broadcastable(a::Foo) = (a,)
b .= foo1

# Success!


Seems like a bug (easily fixable):