Each write operation costs gas. If it expands storage, it costs more gas. Completely clearing a storage slot refunds gas. The refund relates to storage slots, not array elements.
Storage slots are 32-byte, so a uint256
fills a whole slot, whereas a uint8
only fills part of a slot. This means that your adding case is cheaper with uint8
s, because most of the writes overwrite existing storage to cram more stuff in an existing slot, rather than expanding storage.
When you delete, absent optimizations, you have the same number of writes either way, but in the uint8
case most of them are updating the value in the slot, rather than clearing it. You only clear a slot when you remove the last uint8
in it. So you get higher refunds when clearing the uint256
s.