I've noticed that upgradeable ERC721 extension initialisers don't include name/symbol, is this intentional? If so, what's the reasoning for which base classes should/shouldn't initialised in a chained initialiser? What's the intended way to initialise one of these extensions, is it to call the chained initialiser of the extension and then the unchained initialiser of ERC721, or ERC721 chained followed by the extensions unchained?
Yes, it's intentional, and it mirrors the non-upgradeable code. You can see in Contracts Wizard if you select an extension like Enumerable code like the following:
contract MyToken is ERC721, ERC721Enumerable {
constructor() ERC721("MyToken", "MTK") {}
Note how you invoke ERC721's constructor. This is because ERC721Enumerable does not invoke ERC721's constructor even though it extends it, and thus forces "downstream" to have to invoke the constructor in order to get a fully initialized contract.
The same rules apply to upgradeable contracts. The recommendation is that you should call all chained parent initializers, and this is what's implemented in Contracts Wizard. It sounds counterintuitive because some initializers may run more than once, but it turns out that it doesn't have a practical consequence. In the near future our Upgrades Plugins will be able to alert if you accidentally invoke an initializer twice or zero times.
I see, thanks - I haven't used the wizard before so didn't notice this