Why is OI created in robotInit() and not with the Subsystems?

I think there is a difference between robotInit() and the constructor, but most of the time it doesn’t matter. Here’s an old thread talking about it: What's the difference between robotInit() and constructor in SimpleRobot?

Also, note that in kotlin, you can do this:

lateinit var myVariable: MyType

override fun robotInit(){
    myVariable = new MyType()
}

This allows you to not have to check for null and will throw an uninitialized exception.

I’m guessing the WPILib guys made it this way to keep it more similar to c++ and so there’s less confusion for beginners as robotInit() gives more context than just Robot(). Plus, they didn’t design it with kotlin and null safety in mind.