2010-11-23 12 views
14

¿Es posible anular el constructor de estructuras en Fortran? He visto ejemplos propuestos como este (como en la especificación Fortran 2003):Cómo anular un constructor de estructura en fortran

module mymod 

    type mytype 
    integer :: x 
    ! Other stuff 
    end type 

    interface mytype 
    module procedure init_mytype 
    end interface 

contains 
    type(mytype) function init_mytype(i) 
    integer, intent(in) :: i 
    if(i > 0) then 
     init_mytype%x = 1 
    else 
     init_mytype%x = 2 
    end if 
    end function 
end 

program test 
    use mymod 
    type(mytype) :: x 
    x = mytype(0) 
end program 

Esto básicamente genera un montón de errores debidos a redundante nombres de las variables (por ejemplo Error: atributo derivado de conflictos 'MyType' con el atributo PROCEDIMIENTO a la 1)). Una copia textual del ejemplo de Fortran 2003 genera errores similares. Intenté esto en gfortran 4.4, ifort 10.1 y 11.1 y todos producen los mismos errores.

Mi pregunta: ¿es esta una característica no implementada de fortran 2003? ¿O estoy implementando esto incorrectamente?

Editar: He encontrado un bug report y un announced patch para gfortran con respecto a este problema. Sin embargo, he intentado usar una compilación de noviembre de gcc46 sin suerte y errores similares.

Editar 2: El código anterior parece funcionar con Intel Fortran 12.1.0.

Respuesta

6

Consulté mi copia de la norma Fortran 2008. Eso le permite definir una interfaz genérica con el mismo nombre que un tipo derivado. Mi compilador (Intel Fortran 11.1) no compilará el código, por lo que me queda la sospecha (sin una copia del estándar 2003 a mano) de que esta es una característica aún no implementada del estándar Fortran 2003.

Además de eso, hay un error en su programa. Su declaración de la función:

type(mytype) function init_mytype 
    integer, intent(in) :: i 

especifica la existencia y el propósito de una alegación que no está presente en la especificación de la función, que tal vez debería ser reescrita como:

type(mytype) function init_mytype(i) 
+0

gracias, fijo. Disculpas por el error que distrae, fue un ejemplo apresurado. –

17

Is it currently possible to override the structure constructor in Fortran?

todos modos incluso el uso de su enfoque no se trata de la anulación de constructores. La razón principal es que constructor de estructura # OOP constructor. Hay algunas similitudes, pero esta es solo otra idea.

No puede usar su función no intrínseca en la expresión de inicialización. Puede usar solo constante, matriz o constructor de estructura, funciones intrínsecas, ... Para obtener más información, consulte 7.1.7 Expresión de inicialización en el borrador de Fortran 2003.

Teniendo en cuenta ese hecho estoy totalmente de no entiendo cuál es la diferencia real entre

type(mytype) :: x 
x = mytype(0) 

y

type(mytype) :: x 
x = init_mytype(0) 

y lo que es el punto entero de usar interfaz de bloque dentro MÓDULO mimodelo.

Bueno, honestamente hablando hay una diferencia, la enorme: la primera es engañosa. Esta función no es el constructor (porque no hay ningún constructor de OOP en Fortran), es un inicializador.


En la corriente principal constructor de programación orientada a objetos es responsable de hacerlo secuencialmente dos cosas:

  1. de asignación de memoria.
  2. Inicialización de miembros.

Echemos un vistazo a algunos ejemplos de creación de instancias de clases en diferentes idiomas.

En Java:

MyType mt = new MyType(1); 

un hecho muy importante está oculto - el hecho de que el objeto es en realidad un puntero a una varibale de un tipo de clase. El equivalente en C++ será asignación en el montón usando:

MyType* mt = new MyType(1); 

Pero en ambos idiomas se puede ver que dos funciones de constructor se reflejan incluso a nivel de sintaxis. Consta de dos partes: palabra clave nueva (asignación) y nombre del constructor (inicialización). En Objective-C sintaxis este hecho se enfatiza aún más:

MyType* mt = [[MyType alloc] init:1]; 

Muchas veces, sin embargo, se puede ver alguna otra forma de invocación del constructor. En el caso de la asignación en la pila C++ utiliza construcción (muy pobre) sintaxis especial

MyType mt(1); 

que en realidad es una interpretación errónea que simplemente no podemos considerarlo.

En Python

mt = MyType(1) 

tanto el hecho de que el objeto es en realidad un puntero y el hecho de que la asignación tenga lugar primero se ocultan (a nivel de sintaxis). Y este método se llama ... __init__! O_O Tan engañoso. La asignación de stack С ++ se desvanece en comparación con esa. =)


De todos modos, la idea de tener constructor en el lenguaje implica la capacidad de hacer asignación de una inicialización en una declaración el uso de algún tipo especial de método. Y si piensas que este es el "verdadero OOP", tengo malas noticias para ti. Incluso Smalltalkdoesn't have constructors. Es solo una convención tener un método new en las clases en sí (son objetos únicos de metaclases). El Factory Design Pattern se usa en muchos otros idiomas para lograr el mismo objetivo.

Leí en alguna parte que los conceptos de módulos en Fortran estaban inspirados en Modula-2. Y me parece que las características de OOP están inspiradas en Oberon-2. No hay constructores en Oberon-2 también. Pero, por supuesto, hay una asignación pura con el procedimiento predeclarado NUEVO (como ALLOCATE en Fortran, pero ALLOCATE es una declaración). Después de la asignación puede (en la práctica) llamar a un inicializador, que es solo un método ordinario. Nada especial allí.

Así que puede usar algún tipo de factoría para inicializar objetos. Es lo que realmente hiciste usando módulos en lugar de objetos únicos. O es mejor decir que ellos (programadores Java/C#/...) usan métodos de objetos únicos en lugar de funciones ordinarias debido a la falta del último (no hay módulos, no hay forma de tener funciones ordinarias, solo métodos).

También puede usar SUBRUTINES con texto en su lugar.

MODULE mymod 

    TYPE mytype 
    PRIVATE 
    INTEGER :: x 
    CONTAINS 
    PROCEDURE, PASS :: init 
    END TYPE 

CONTAINS 

    SUBROUTINE init(this, i) 
    CLASS(mytype), INTENT(OUT) :: this 
    INTEGER, INTENT(IN) :: i 

    IF(i > 0) THEN 
     this%x = 1 
    ELSE 
     this%x = 2 
    END IF 
    END SUBROUTINE init 

END 

PROGRAM test 

    USE mymod 

    TYPE(mytype) :: x 

    CALL x%init(1) 

END PROGRAM 

INTENT(OUT) para this arg de init SUBRUTINA parece estar bien. Porque esperamos que este método se invoque solo una vez e inmediatamente después de la asignación. Puede ser una buena idea controlar que esta suposición no sea incorrecta. Para agregar un indicador booleano LOGICAL :: inited a mytype, compruebe si es .false. y configúrelo en .true. con la primera inicialización, y haga algo más cuando intente reinicializar. Definitivamente recuerdo algún hilo al respecto en Google Groups ... No puedo encontrarlo.

+2

Gracias por la aclaración. Entiendo que no es un constructor en el sentido de POO purista, y que enfoques alternativos similares lograrán la mayoría de las mismas cosas. Más bien, este es un ejemplo casi literal de p445 (C.1.6) que los autores han elegido llamar "constructor de estructura" en uno de los borradores de trabajo de especificaciones. Me preguntaba si tal anulación era actualmente posible en implementaciones comunes de fortran. Pero tomaré en serio tu consejo, gracias de nuevo. –