Yes, you do need a certain level of indirection to achieve the things you mentioned without polluting your code with non-business concerns such as transactionality. But the key differences are:
1. Application startup is faster because you avoid reflection.
2. It's type-safe because you avoid reflection, so you get compile-time errors instead of startup errors (or worse, startup errors only in certain configurations).
3. It gives you more inspectable behaviour. You can see how the entrypoint of the application wires together components. A lot of this can be hidden, spread out over multiple places and hard to understand otherwise.
Also, I'm not the person you originally replied to, didn't call DI a circus, and actually think that DI is a useful concept per se (that some FP purists maybe under-appreciate): It could just IMHO be done in a cleaner way (and a more deliberate way, not everything needs to be wrapped in 5 layers :)) with functional constructs instead of reflection hell. :D
1. Application startup is faster because you avoid reflection.
2. It's type-safe because you avoid reflection, so you get compile-time errors instead of startup errors (or worse, startup errors only in certain configurations).
3. It gives you more inspectable behaviour. You can see how the entrypoint of the application wires together components. A lot of this can be hidden, spread out over multiple places and hard to understand otherwise.
Also, I'm not the person you originally replied to, didn't call DI a circus, and actually think that DI is a useful concept per se (that some FP purists maybe under-appreciate): It could just IMHO be done in a cleaner way (and a more deliberate way, not everything needs to be wrapped in 5 layers :)) with functional constructs instead of reflection hell. :D