En Delphi 7, ¿por qué puedo asignar un valor a un const?

Copié un código Delphi de un proyecto a otro y descubrí que no se comstack en el nuevo proyecto, aunque sí en el anterior. El código se ve así:

procedure TForm1.CalculateGP(..) const Price : money = 0; begin ... Price := 1.0; ... end; 

Entonces, en el nuevo proyecto, Delphi se queja de que “el lado izquierdo no puede asignarse a”, ¡comprensible! Pero este código se comstack en el proyecto anterior. Entonces mi pregunta es, ¿por qué ? ¿Hay un cambio de comstackdor para permitir reasignar consts? ¿Cómo funciona eso? Pensé que las constelaciones fueron reemplazadas por sus valores en tiempo de comstackción.

Debe activar las constantes tipeadas asignables. Proyecto -> Opciones -> Comstackdor -> Constantes tipadas asignables

También puede agregar {$J+} o {$WRITEABLECONST ON} al archivo pas, que probablemente sea mejor, ya que funcionará incluso si mueve el archivo a otro proyecto.

Las constantes de tipo inferido solo pueden ser valores escalares, es decir, cosas como enteros, dobles, etc. Para este tipo de constantes, el comstackdor sí reemplaza el símbolo de la constante con el valor de la constante siempre que los encuentre en expresiones.

Las constantes tipadas, por otro lado, pueden ser valores estructurados: matrices y registros. Estos tipos necesitan almacenamiento real en el ejecutable, es decir, necesitan tener almacenamiento asignado para ellos de forma tal que, cuando el sistema operativo cargue el ejecutable, el valor de la constante tipeada esté físicamente contenido en alguna ubicación de la memoria.

Para explicar por qué, históricamente, las constantes tipadas en Delphi inicial y su predecesor, Turbo Pascal, son escribibles (y, por lo tanto, esencialmente variables globales inicializadas), tenemos que volver a los días de DOS.

DOS se ejecuta en modo real, en términos x86. Esto significa que los progtwigs tienen acceso directo a la memoria física sin que ninguna MMU realice asignaciones virtuales-físicas. Cuando los progtwigs tienen acceso directo a la memoria, no hay protección de memoria en efecto. En otras palabras, si hay memoria en cualquier dirección dada, es legible y escribible en modo real.

Entonces, en un progtwig Turbo Pascal para DOS con una constante tipada, cuyo valor se asigna a una dirección en la memoria en tiempo de ejecución, esa constante tipeada será escribible. No hay una MMU de hardware que se interponga y que impida que el progtwig escriba en ella. De manera similar, debido a que Pascal no tiene noción de ‘const’ness’ que C ++ tiene, no hay nada en el sistema de tipos que lo detenga. Mucha gente se aprovechó de esto, ya que Turbo Pascal y Delphi en ese momento no habían inicializado las variables globales como una característica.

Pasando a Windows, hay una capa entre las direcciones de memoria y físicas: la unidad de gestión de memoria. Este chip toma el índice de página (una máscara desplazada) de la dirección de memoria a la que intenta acceder y busca los atributos de esta página en su tabla de páginas . Estos atributos incluyen legibles, editables, y para chips modernos x86, indicadores no ejecutables. Con este soporte, es posible marcar secciones de .EXE o .DLL con atributos tales que cuando el cargador de Windows carga la imagen ejecutable en la memoria, asigna atributos de página apropiados para las páginas de memoria que asignan páginas de disco dentro de estas secciones.

Cuando apareció la versión de Windows de 32 bits del comstackdor Delphi, tenía sentido hacer que las cosas parecidas a const fuesen realmente reales, ya que el sistema operativo también tiene esta característica.

  1. Por qué: debido a que en las versiones anteriores de Delphi, las constantes tipadas se podían asignar de forma predeterminada para preservar la compatibilidad con versiones anteriores en las que siempre podían escribirse (Delphi 1 hasta principios de Pascal).
    El valor predeterminado ahora se ha cambiado para hacer que las constantes sean realmente constantes …

  2. Conmutador del comstackdor: {$ J +} o {$ J-} ​​{$ WRITEABLECONST ON} o {$ WRITEABLECONST OFF}
    O en las opciones de proyecto para el comstackdor: verificar Constantes tipeables asignables

  3. Cómo funciona: si el comstackdor puede calcular el valor en tiempo de comstackción, reemplaza la const por su valor en todas partes del código, de lo contrario, mantiene un puntero a un área de memoria que contiene el valor, que puede escribirse o no.
  4. ver 3.

Como dijo Barry, la gente se aprovechó de las constelaciones; Una de las formas en que esto se usó fue para realizar un seguimiento de las instancias únicas. Si observas una implementación singleton clásica, verías esto:

  // Example implementation of the Singleton pattern. TSingleton = class(TObject) protected constructor CreateInstance; virtual; class function AccessInstance(Request: Integer): TSingleton; public constructor Create; virtual; destructor Destroy; override; class function Instance: TSingleton; class procedure ReleaseInstance; end; constructor TSingleton.Create; begin inherited Create; raise Exception.CreateFmt('Access class %s through Instance only', [ClassName]); end; constructor TSingleton.CreateInstance; begin inherited Create; // Do whatever you would normally place in Create, here. end; destructor TSingleton.Destroy; begin // Do normal destruction here if AccessInstance(0) = Self then AccessInstance(2); inherited Destroy; end; {$WRITEABLECONST ON} class function TSingleton.AccessInstance(Request: Integer): TSingleton; const FInstance: TSingleton = nil; begin case Request of 0 : ; 1 : if not Assigned(FInstance) then FInstance := CreateInstance; 2 : FInstance := nil; else raise Exception.CreateFmt('Illegal request %d in AccessInstance', [Request]); end; Result := FInstance; end; {$IFNDEF WRITEABLECONST_ON} {$WRITEABLECONST OFF} {$ENDIF} class function TSingleton.Instance: TSingleton; begin Result := AccessInstance(1); end; class procedure TSingleton.ReleaseInstance; begin AccessInstance(0).Free; end;