Visibility of initializer function in upgradable smart contracts

The upgradable contract implements an initializer function that only initializes once - somewhat mimicking constructor behavior. Now since the new Ethereum upgrade visibility operands have been removed from constructors:

Visibility (public / external) is not needed for constructors anymore: To prevent a contract from being created, it can be marked abstract. This makes the visibility concept for constructors obsolete.


How come all examples for using initializer are declared public?

Here I would assume that the initializer has no inherent relation with the EVM with respect to being considered a constructor other than the fact that it is a function with the caveat of only being allowed to be initialized once.

Now with respect to being declared public - is the reason because they are operated via delegatecall - and hence need to be callable externally?

If that is the case surely there should be sensible use cases to mark such a function as - for example - external.

In that sense there ought to exist a derivation of best practices with respect to initializer functions for upgradability, with recommendations as to when such a function for such a contract is recommended to be:

private / internal / external/public

Yes, it needs to be callable externally.

The distinction between public and external is not really significant. It only makes a difference if you will also need to call the initializer internally, for example if you will inherit from that contract and need to initialize it from the child contract.