02-elementwise-ops's functions all quietly relied on something never actually explained: adding a scalar to an array, or combining two differently-shaped arrays, just worked. That "just works" is called broadcasting, and it isn't magic, it's a precise rule about which shapes are allowed to combine and what shape the result gets. Without knowing the rule exactly, you can't predict when two mismatched shapes will silently combine (possibly computing something you didn't intend) versus when they'll correctly raise an error, and that unpredictability is exactly where subtle shape bugs come from later in this curriculum.
Implement broadcast_shapes(shape_a, shape_b), returning the shape two arrays of those shapes would broadcast to, or None if they're incompatible. Theory's alignment-from-the-right-then-compare-pairwise procedure maps directly onto the function: pad the shorter shape, then walk both shapes together checking one compatibility condition per dimension.
1s on the left, not the right.1.max(dim_a, dim_b).None immediately — there's no such thing as a partial broadcast.() scalar shape) and shapes of equal length.Open one at a time. Each gives away a little more than the last.
"Aligned from the right" means the last dimension of shape_a pairs with the last dimension of shape_b, the second-to-last with the second-to-last, and so on. Before you can zip two shapes together pairwise, you need them to be the same length — how would you make the shorter one longer without changing what it means?
Padding must happen on the left: (1,) * len_diff + tuple(shorter_shape). Padding on the right would silently misalign every dimension in the shorter shape against the wrong dimension in the longer one.
Click "Run Tests" to test your implementation