I posted substantially this document to the Racket Discourse for
discussion; I'd like to consider these issues here, too, if there is
some interest.
Brad
TL;DR version:
Applying array broadcasting to mutable or non-strict arrays can be very
difficult to reason about, so should one restrict broadcasting to
strict, immutable arrays? or ignore the difficulties and learn to love
array broadcasting because it's useful and can be efficient?
Some examples and questions follow.
I've been trying to understand how the features of array broadcasting,
mutability, and non-strict arrays interact in math/array, and how they
might interact in other frameworks.
For example, one might make the bare call with explicit broadcasting
(define brr0 (array-broadcast arr0 ds))
or have a call with implicit broadcasting
(define brr1 (array-map * arr1 arr2 arr3))
where arr1, arr2, and arr3 are arrays with different, but compatible,
shapes for broadcasting.
First, if brr0 is mutable (meaning that arr0 is mutable, which in
math/array means arr0 is strict), then
(array-set! brr0 #(1 2) val)
may happen to change all entries of brr0 with first index 1, or second
index 2, or change the values of all entries of brr0 entirely.
It is nearly impossible to reason about programs where this can happen,
so perhaps broadcasting should be limited to immutable arrays.
In the second example, if arr1, arr2, or arr3 are broadcast, then the
broadcast version is "consumed" by (array-map * ...), and array-set!
cannot be applied directly to the broadcast arguments.
But here now if a non-strict array arr1 is broadcast, and computing an
element of arr1 has side effects, then computing
(array-all-sum brr1)
may cause those side effects may be executed an undetermined number of
times.
Which again may lead to unclear exceptions and behavior that about which
it is difficult to reason.
Or should we not worry about such things, say that some uses of such
forms are very convenient, and learn not to ask such questions.