As an exercise, I wrote some code to translate between ROS topics and services. Both directions turned out to be somewhat tricky. For example, I had to use a condition variable to coordinate updating data from the topic (which is taken care of behind the scenes in ROS using a provided callback) with calls to the service. I couldn't figure out whether the way the callback is used under the hood is thread safe, so there may be some extraneous locking in my solution.
Going the other direction is complicated by the fact that service request and response objects, which walk and talk like messages, aren't actually messages. So populating a call to a service and reading the response requires specifying some code in advance that knows how to translate a service response into a proper message. You can't use the response object as a topic message type directly since it's not actually a visible message type and roscore will complain that it can't find the message definition.
In general, it would be nice if services and messages could be specified dynamically, but I suspect that the performance requirements of serialization require that these be specified in advance and compiled.