2010-11-23 15 views
14

È attualmente possibile eseguire l'override del costruttore di strutture in Fortran? Ho visto esempi proposti come questo (come ad esempio nel Fortran spec 2003):Come eseguire l'override di un costruttore di strutture in 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 

Questo genera fondamentalmente un mucchio di errori dovuti a ridondanti nomi delle variabili (ad esempio Errore: attributo derivati ​​conflitti 'MyType' con l'attributo PROCEDURA a (1)). Una copia letterale dell'esempio di fortran 2003 genera errori simili. Ho provato questo in gfortran 4.4, ifort 10.1 e 11.1 e tutti producono gli stessi errori.

La mia domanda: questa è solo una caratteristica non implementata di Fortran 2003? O sto implementando questo in modo errato?

Modifica: ho trovato uno bug report e un announced patch su gfortran per quanto riguarda questo problema. Tuttavia, ho provato a utilizzare una build di novembre di gcc46 senza errori di fortuna e simili.

Modifica 2: il codice sopra sembra funzionare utilizzando Intel Fortran 12.1.0.

risposta

6

Ho consultato la mia copia dello standard Fortran 2008. Ciò consente di definire un'interfaccia generica con lo stesso nome di un tipo derivato. Il mio compilatore (Intel Fortran 11.1) non compilerà il codice, quindi sono rimasto a sospettare (senza una copia dello standard 2003 a portata di mano) che questa è una funzionalità ancora non implementata dello standard Fortran 2003.

Oltre a ciò, c'è un errore nel programma. La vostra dichiarazione di funzione:

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

specifica l'esistenza e l'intento di un argomento che non è presente nella specifica funzione, che dovrebbe forse essere riscritta come:

type(mytype) function init_mytype(i) 
+0

grazie, risolto. Ci scusiamo per l'errore di distrazione, è stato un esempio affrettato. –

17

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

No. Comunque anche l'utilizzo del tuo approccio non riguarda completamente la sostituzione del costruttore. Il motivo principale è il costruttore della struttura # OOP costruttore. C'è qualche somiglianza ma questa è solo un'altra idea.

Non è possibile utilizzare la funzione non intrinseca nell'espressione di inizializzazione. È possibile utilizzare solo costante, costruttore di strutture o struttura, funzioni intrinseche, ... Per ulteriori informazioni, consultare 7.1.7 Espressione di inizializzazione in Bozza di Fortran 2003.

Prendendo tale circostanza conto Sono completamente non comprendo qual è la vera differenza tra

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

e

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

e qual è il punto di utilizzare blocco INTERFACE all'interno MODULO mymod.

Beh, onestamente, c'è una differenza, quella enorme: il primo modo è fuorviante. Questa funzione non è il costruttore (perché in Fortran non ci sono costruttori OOP), è un inizializzatore.


Nel costruttore OOP corrente principale è responsabile per sequenziale fare due cose:

  1. di allocazione della memoria.
  2. Inizializzazione membro.

Diamo un'occhiata ad alcuni esempi di classi di istanziazione in diverse lingue.

In Java:

MyType mt = new MyType(1); 

un fatto molto importante è nascosto - il fatto che l'oggetto è in realtà un puntatore ad una varibale di un tipo di classe. L'equivalente in C++ sarà allocazione sul mucchio utilizzando:

MyType* mt = new MyType(1); 

Ma in entrambe le lingue si vede che due funzioni costruttore si riflettono anche a livello sintassi. Consiste di due parti: parola chiave nuova (allocazione) e nome costruttore (inizializzazione). In Objective-C sintassi questo fatto è ancora più enfatizzato:

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

Molte volte, però, si può vedere qualche altra forma di costruttore di invocazione. Nel caso di allocazione sulla pila C++ utilizza speciale costruzione (molto scarso) sintassi

MyType mt(1); 

che in realtà è così fuorviante possiamo solo non considerarlo.

In Python

mt = MyType(1) 

sia fatto l'oggetto è in realtà un puntatore e il fatto che l'assegnazione avvengono prima sono nascosti (a livello di sintassi). E questo metodo è chiamato ... __init__! O_O Quindi fuorviante. Lo stack stacking di С ++ sfuma in confronto a quello. =)


In ogni caso, l'idea di avere costruttore nella lingua implica la capacità di fare allocazione un'inizializzazione in una dichiarazione usando qualche particolare tipo di metodo. E se pensi che questo sia un modo "vero OOP", ho brutte notizie per te. Anche Smalltalkdoesn't have constructors. È solo una convenzione avere un metodo new sulle classi stesse (sono oggetti singleton di meta-classi). Lo Factory Design Pattern è utilizzato in molti altri linguaggi per raggiungere lo stesso obiettivo.

ho letto da qualche parte che i concetti di moduli in Fortran è stato ispirato da Modula-2. E mi sembra che le funzionalità di OOP siano ispirate allo Oberon-2. Non ci sono costruttori in Oberon-2 anche. Ma naturalmente c'è una pura allocazione con la procedura predeterminata NEW (come ALLOCATE in Fortran, ma ALLOCATE è una dichiarazione). Dopo l'allocazione è possibile (dovrebbe in pratica) chiamare un inizializzatore, che è solo un metodo normale. Niente di speciale lì.

Quindi è possibile utilizzare alcune specie di fabbriche per inizializzare gli oggetti. È quello che hai effettivamente fatto usando i moduli invece degli oggetti singleton. Oppure è meglio dire che essi (programmatori Java/C#/...) usano metodi di oggetti singleton invece di funzioni ordinarie a causa della mancanza di quello successivo (nessun modulo - nessun modo per avere funzioni ordinarie, solo metodi).

Inoltre, è possibile utilizzare SUBROUTINE con tipo vincolato.

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) per this arg di init SUBROUTINE sembra essere fine. Perché ci aspettiamo che questo metodo venga chiamato solo una volta e subito dopo l'allocazione. Potrebbe essere una buona idea controllare che questa ipotesi non sia sbagliata. Per aggiungere qualche bandiera booleana LOGICAL :: inited a mytype, verificare se è .false. e impostarlo su .true. alla prima inizializzazione e fare qualcos'altro al tentativo di reinizializzazione. Ricordo sicuramente alcuni thread su di esso in Google Gruppi ... Non riesco a trovarlo.

+2

Grazie per il chiarimento. Capisco che non è un costruttore nel senso purista dell'OOP, e che approcci alternativi simili realizzeranno la maggior parte della stessa cosa. Piuttosto, questo è un esempio quasi completo di p445 (C.1.6) che gli autori hanno scelto di chiamare un "costruttore di strutture" in una delle bozze di lavoro specifiche. Mi chiedevo se una tale sovrascrittura fosse attualmente possibile nelle implementazioni comuni di Fortran. Ma porterò a cuore il tuo consiglio, grazie ancora. –

Problemi correlati