Uno de los problemas sería que, en muchos casos, la clave para la tabla hash sería una cadena. Por lo tanto, los consumidores del método tendrían que saber de antemano qué teclas utilizar para extraer los datos. Esto daría la posibilidad de errores debido a errores ortográficos al acceder a los datos.
Otro inconveniente es la refactorabilidad. Si luego decides cambiar el nombre de un miembro, entonces tienes un montón de cadenas mágicas que también necesitan cambiar. Es mucho más simple cambiar el nombre de un miembro de la clase utilizando las herramientas de refactorización proporcionadas por la mayoría de los buenos IDE. Con una tabla hash, es probable que tenga que hacer una operación de búsqueda / reemplazo en todos los archivos de origen, lo que podría ser problemático.
Por último, perderá tiempo de compilación comprobando el acceso de los miembros, tanto en términos de nombre como de tipo. Este último no es un problema si su tabla hash solo contiene un tipo de objeto, pero si contiene muchos (incluso en la misma cadena jerárquica) realmente desea aprovechar el sistema de tipos de su idioma y obtener tiempo de compilación comprobando allí. En la mayoría de los IDE, tendrá algún tipo de funciones intellisense / autocompletar: funcionan al observar el sistema de tipos, pero no podrán ayudarlo con las teclas de tabla hash.
En cuanto a los momentos en que sería apropiado devolver una tabla hash (u otra colección de pares de valores de clave), lo usaría cuando no se conocen los valores y las claves en el momento de la compilación. Por ejemplo, si tiene un método que analiza una cadena de consulta y devuelve las claves y los valores correspondientes, una tabla hash sería una buena opción. En este caso, también querrás pensar en devolver algún tipo de tabla hash inmutable o de solo lectura.
Editar : la mayoría de los puntos planteados en esta respuesta dejan de aplicarse cuando se habla de lenguajes dinámicos :)