polimorfico - ejemplo de un constructor en c#
La diferencia entre un destructor y un finalizador? (4)
Nota: esta pregunta es sobre la diferencia de terminología entre las palabras "destructor" y "finalizador" y su uso correcto. Simplemente proporcioné ejemplos de su uso en C # y C ++ / CLI para demostrar por qué hago la pregunta. Soy muy consciente de cómo se implementa en C # y CLR, pero estoy preguntando sobre el uso correcto de la terminología.
En el mundo de C #, los términos "destructor" y "finalizador" parecen usarse de manera bastante intercambiable, lo que sospecho es porque la especificación C # describe la funcionalidad de limpieza no determinista usando la palabra "destructor", mientras que la documentación CLR siempre usa el palabra "finalizador", por lo que dentro de los reinos de C # significan lo mismo.
Sin embargo, en la especificación C ++ / CLI hay una distinción entre los dos. Permite la limpieza determinista y no determinista, y utiliza el término "destructor" para la funcionalidad determinista y "finalizador" para la funcionalidad no determinista:
El finalizador proporciona una limpieza no determinista. Un finalizador es una función de "última oportunidad" que se ejecuta durante la recolección de basura, generalmente en un objeto cuyo destructor no se ejecutó.
Además, las descripciones de Wikipedia de destructor y finalizer indican que los destructores y los finalizadores son conceptos separados, y son compatibles con el uso de los términos de C ++ / CLI en relación con el determinismo:
A diferencia de los destructores, los finalizadores no son deterministas. Se ejecuta un destructor cuando el programa libera explícitamente un objeto. Un finalizador, por el contrario, se ejecuta cuando el sistema interno de recolección de basura libera el objeto.
Las preguntas:
¿Existe, desde el punto de vista de la informática, una diferencia claramente definida entre un "destructor" y un "finalizador", o es la terminología algo que solo puede definirse contextualmente?
Si hay una diferencia claramente definida, ¿por qué la especificación C # usaría la terminología "incorrecta"?
1) ¿Existe una diferencia bien definida entre "destructor" y "finalizador" tal como se usa en la industria o la academia?
Ciertamente parece ser así. La diferencia parece ser que los destructores son métodos de limpieza que se invocan determinísticamente, mientras que los finalizadores se ejecutan cuando el recolector de basura les dice que lo hagan.
2) En ese caso, la especificación de C # se equivoca: los finalizadores se llaman "destructores" en C #. ¿Por qué los autores de la especificación de C # lo malinterpretaron?
No lo sé, pero puedo adivinar. De hecho, tengo dos conjeturas.
Guess # 1 es que el 12 de mayo de 1999 no había un artículo en la wikipedia que describiera claramente la sutil diferencia entre estos dos conceptos. Eso es porque no había una wikipedia. ¿Recuerdas cuando no había una wikipedia? Edades oscuras, hombre. El error podría haber sido simplemente un error honesto, al creer que los dos términos eran idénticos.
Diablos, por lo que sé, los dos términos fueron idénticos el 12 de mayo de 1999, y la diferencia en las definiciones solo evolucionó más tarde, ya que se hizo evidente que había una necesidad de eliminar la ambigüedad entre los métodos de limpieza ansiosos y perezosos.
Guess # 2 es que el 12 de mayo de 1999, el comité de diseño de idiomas deseaba dejar abierta la posibilidad de que un "destructor" pudiera implementarse como algo más que un finalizador. Es decir, el "destructor" se diseñó para ser un concepto de lenguaje C # que no necesariamente se correlacionaba uno a uno con el concepto de "finalizador" de .NET. Al diseñar un idioma al mismo tiempo que el marco en el que se encuentra, también se está diseñando, a veces uno quiere aislarse contra los cambios de diseño de última hora en sus subsistemas.
Las notas del comité de idiomas para el 12 de mayo de 1999 se leen en parte:
Vamos a usar el término "destructor" para el miembro que se ejecuta cuando se reclama una instancia. Las clases pueden tener destructores; las estructuras no pueden. A diferencia de C ++, un destructor no puede ser llamado explícitamente. La destrucción no es determinista: no se puede saber con certeza cuándo se ejecutará el destructor, excepto para decir que se ejecuta en algún momento después de que se hayan liberado todas las referencias al objeto. Los destructores en una cadena de herencia se llaman en orden, de la mayoría de los descendientes a los descendientes. No hay necesidad (y no hay forma) para que la clase derivada llame explícitamente al destructor base. El compilador de C # compila destructores para la representación de CLR apropiada. Para esta versión, probablemente se trate de un finalizador de instancia que se distingue en metadatos. CLR puede proporcionar finalizadores estáticos en el futuro; no vemos ninguna barrera para C # usando finalizadores estáticos.
Entonces, allí, ahora sabes todo lo que sé sobre el tema. Si quieres saber más, pregúntale a Anders la próxima vez que lo veas.
Creo que ''destructor'' es el código C #, y el ''finalizador'' es el método compilado CIL. El compilador de C # convierte un destructor en un finalizador.
EDITAR: Para ser más detallado; La especificación del lenguaje C # define un ''destructor'' como un método de instancia C # en una clase. ''destructor'', entonces, es parte de la gramática C # - los destructores son un objeto lingüístico que aparece en el código fuente.
Un destructor es un miembro que implementa las acciones necesarias para destruir una instancia de una clase. Los destructores no pueden tener parámetros, no pueden tener modificadores de accesibilidad y no pueden invocarse explícitamente. El destructor de una instancia se invoca automáticamente durante la recolección de basura.
Un ''finalizador'' es un término utilizado en Common Language Runtime, por ejemplo, en llamadas a GC.WaitForPendingFinalizers()
, y se refiere a cualquier lenguaje .net, no solo a C #. Cualquier tipo de referencia .net puede tener un finalizador. Para una clase C # (el artefacto del código fuente), el destructor se compila en el método CIL, que es el finalizador del tipo CLR.
O más sucintamente, destructor es para el finalizador como el código fuente es para el código máquina ;)
Si nos atenemos a la definición "determinista" de destructores, entonces diría que en los objetos .NET no tienen destructores a menos que se implementen explícitamente mediante el uso de la interfaz IDisposable .
Estrictamente hablando C # no tiene un destructor (creo que la especificación de C # es confusa en este punto). El finalizador de C # se parece a un destructor de C ++ pero, como dices, no es determinista. C # tiene una limpieza determinista en forma de IDisposable::Dispose
(pero esto todavía no se llama destructor).
C ++ / CLI tiene destructores deterministas, que se parecen a los destructores de C ++. En el nivel CLI, estos mapas se IDisposable::Dispose()
en IDisposable::Dispose()
( IDisposable
se implementa para usted). C ++ / CLI tiene finalizadores no deterministas, que parecen destructores pero usan el! prefijo en lugar del prefijo ^.
El hecho de que C ++ / CLI use la misma sintaxis para los destructores que C # usa para los finalizadores puede ser un poco confuso, pero se ajusta mejor a C ++, que tiene una fuerte tradición de destrucción determinista.
Desafortunadamente, la falta de definiciones universales de estos términos significa que siempre necesita aclarar de qué está hablando. Personalmente siempre utilizo la palabra finalizador cuando hablo sobre el concepto de C # y reservo destructor para contextos en los que definitivamente implica destrucción determinística.
[Actualización] Desde mi publicación original aquí, Eric Lippert ha publicado su respuesta (la respuesta aceptada) y ha seguido con una publicación en el blog sobre la misma. Me alegra ver que estamos de acuerdo :-)