... you can use non-string keys if you need to (or: someone who extends your module can add non-string stuff without breaking all pre-existing code).
I don't understand this point. Isn't it always possible to use 'non-string' (actually non-bareword) keys as long as they are appropriately disambiguated? Anyone who is aware of the calling convention of your module (as they surely must be to extend the module or to use it in the first place) can easily avoid this pitfall.
The classic example:
You have a constant KONSTANT (defined with the use constant ... pragma) that you want to use as a key.
Then just disambiguate KONSTANT as the function call it really is:
func({ KONSTANT() => 'foo' });
Leaving aside a multitude of ambiguities arising from confusion about the precedence of the , (comma) and => operators versus other operators, it's hard to imagine another realistic example in which this problem would arise.