Es necesario algún tipo de indirección para programas complejos (por ejemplo, estructuras de datos recursivas o de tamaño variable). Sin embargo, no es necesario implementar esta indirección a través de punteros.
La mayoría de los lenguajes de programación de alto nivel (es decir, no ensamblados) son bastante seguros para la memoria y no permiten el acceso sin restricciones del puntero. La familia C es la extraña aquí.
C evolucionó de B, que era una abstracción muy delgada sobre el ensamblaje sin procesar. B tenía un solo tipo: la palabra. La palabra podría usarse como un entero o como un puntero. Esos dos son equivalentes cuando toda la memoria se ve como una única matriz contigua. C mantuvo este enfoque bastante flexible y continuó apoyando la aritmética de puntero inherentemente insegura. Todo el sistema de tipos de C es más una idea de último momento. Esta flexibilidad para acceder a la memoria hizo que C fuera muy adecuado para su propósito principal: crear prototipos del sistema operativo Unix. Por supuesto, Unix y C resultaron ser bastante populares, por lo que C también se usa en aplicaciones donde este enfoque de bajo nivel para la memoria no es realmente necesario.
Si observamos los lenguajes de programación anteriores a C (p. Ej., Dialectos de Fortran, Algol, incluidos Pascal, Cobol, Lisp, ...), algunos de ellos admiten punteros tipo C. Notablemente, el concepto de puntero nulo fue inventado para Algol W en 1965. Pero ninguno de esos lenguajes trató de ser un lenguaje de sistemas de baja abstracción eficiente tipo C: Fortran estaba destinado a la computación científica, Algol desarrolló algunos conceptos bastante avanzados, Lisp fue más de un proyecto de investigación que un lenguaje de grado industrial, y Cobol se centró en aplicaciones comerciales.
La recolección de basura existió desde finales de los años 50, es decir, mucho antes de C (principios de los 70). GC requiere seguridad de memoria para funcionar correctamente. Los lenguajes anteriores y posteriores a C utilizaron GC como característica normal. Por supuesto, eso hace que un lenguaje sea mucho más complicado y posiblemente más lento, lo que fue especialmente notable en la época de los mainframes. Los lenguajes GC tienden a estar orientados a la investigación (por ejemplo, Lisp, Simula, ML) y / o requieren estaciones de trabajo potentes (por ejemplo, Smalltalk).
Con computadoras más pequeñas y potentes, la informática en general y los lenguajes GC específicamente se hicieron más populares. Para aplicaciones que no son en tiempo real (y a veces incluso entonces) GC es ahora el enfoque preferido. Pero los algoritmos de GC también han sido objeto de una intensa investigación. Como alternativa, también se ha desarrollado aún más la seguridad de la memoria sin GC, especialmente en las últimas tres décadas: innovaciones notables son RAII y punteros inteligentes en C ++ y el sistema de verificación de vida / préstamo de Rust.
Java no innovó al ser un lenguaje de programación seguro para la memoria: básicamente tomó la semántica del lenguaje Smalltalk GCed, seguro para la memoria y los combinó con la sintaxis y la tipificación estática de C ++. Luego se comercializó como un C / C ++ mejor y más simple. Pero solo es superficialmente un descendiente de C ++. La falta de punteros de Java se debe mucho más al modelo de objetos Smalltalk que al rechazo del modelo de datos C ++.
Por lo tanto, los lenguajes "modernos" como Java, Ruby y C # no deben interpretarse como la superación de los problemas de los punteros en bruto como en C, sino que deben verse como dibujados de muchas tradiciones, incluido C, pero también de lenguajes más seguros como Smalltalk, Simula, o Lisp.