"Just" a multi-threaded app and calling functions isn't really a good replacement. For something really basic, sure, but the modularity that ROS introduces, and the core principle of having serialisable recordable messages delivers a lot of value once you start building large systems - particularly those that can span multiple physical machines. But pub-sub is _too_ general as a concurrency model, if ROS had adopted something more constrained that was provably deterministic and was amenable to real time analysis then a lot of its concerns would go away.