@esc24 and I have had an *extensive* offline discussion around the thorny issues of fill values. The highlights which have stuck in my head are:
 - Fill values are a major pain in the [body_part]. There is no right answer so we have to make some pragmatic choices.
 - Because we have a mask, fill values are only really relevant when saving to disk.
 - The two vaguely coherent, alternative (i.e. competing) perspectives on fill values are:
  1. They are purely suggestive. The mask has primacy.
  2. They should always be consistent with the data.

Of these, we prefer option (i).

So, our current plan of attack is:
 - Make Cube.data *always* a np.ma.MaskedArray (albeit sometimes supplied by a biggus.Array). This includes removing the count/unmask logic.
  - (You will still be able to set a cube's data with a simple np.ndarray instance, but it will be promoted to a masked array.)
 - Preserve fill values from load.
 - Preserve fill values where possible through merge and analysis operations (although with no guarantee of correctness).
 - Only use the fill value when saving. The save operations would also check for unmasked values which collide with the fill value and issue a warning/error.

Some of the second-order changes required are:
 - Modify biggus so that it allows heterogeneous fill values within an ArrayStack.
 - Avoid having Cube.fill_value. (To avoid merge (and others) poking around in cube internals, this might involve exposing the biggus/numpy duality.)

This addresses the `cube.fill_value is None` issue shown in the previous comment in two ways. Firstly, cube.fill_value won't exist, but even if it did it would never be None.