Moduli Fortran
La possibilità di decomporre un problema complesso in
sottoproblemi più semplici è cruciale
per la scrittura del software e, nei linguaggi di tipo imperativo
come Fortran, C, Pascal, Basic, corrisponde alla
possibilità di definire dei sottoprogrammi ciascuno
dei quali implementi solo parte o meglio un sottoalgoritmo dell'
algoritmo complessivo.
Il Fortran, per ragioni storiche, ha diversi tipi di
sottoprogramma. In questo corso ci limiteremo a function e subroutine. Inoltre, anche se
il linguagio permette un impiego di questi sottoprogrammi come
entità indipendenti, salvo mettere a disposizione la
possibilità di costruire interfacce esplicite per
assicurare la consistenza nella comunicazione dei dati tra
programma chamante e sottoprogramma, limiteremo ulteriormente l'
impiego di subroutine e function all' utilizzo all' interno
dei moduli.
Le ragioni per preferire l' uso dei sottoprogrammi all'
interno dei moduli sono diverse:
- i moduli comportano la costruzione dell' interfaccia da
parte del compilatore, semplificando il compito del programmatore;
- L' utilizzo di tipi derivati come argomenti formali o
valori di ritorno di sottoprogrammi, pur essendo possibile, non
è diretto e può generare problemi di
efficienza;
- i moduli permettono un migliore controllo sull'
accessibilità, eventualmente parziale, di
più sottoprogrammi tra loro collegati,
migliorando la moduarità del codice;
- i moduli permettono di emulare gran parte delle
funzionalità delle classi del paradigma di programmazione
ad oggetti, in cui l' accento viene spostato dai
sottoprogrammi ai dati su cui questi agiscono. In effetti i
moduli permettono di relizzare un legame stretto, a livello del codice,
tra dati e sottoprogrammi ad essi collegati.
Schematicamente un modulo è costituito da un blocco di
istruzioni comprese tra le due istruzioni
module nome_modulo
...
end module nome_modulo
Dove nome_modulo
è un qualsiasi nome valido Fortran
(stringa di max 31 caratteri, solo alfanumerici e underscore
("_"), con l' obbligo di non iniziare con una cifra.
Nel modulo ci possono essere una o due sezioni. Se
c'è la seconda, il suo inizio viene segnalato dalla
parole CONTAINS.
Nella prima sezione vanno obbligatoriamente le dichiarazioni di
variabili e costanti del modulo, i tipi dati derivati
e le eventuali dichiarazioni di carattere pubblico o privato delle
entità definite nel modulo o la richiesta che i dati siano
conservati tra un utilizzo ed un altro del modulo stesso. Tutto
ciò che viene dichiarato privato ( PRIVATE ) nel modulo
non è visibile nelle procedure che utilizzano il modulo.
L' istruzione
PRIVATE
rende "private" l' attributo di default di ogni entita' del modulo.
E' consigliabile iniziare ogni modulo con l' istruzione SAVE
in modo che il valore dei campi dati eventualmente definiti nel modulo siano preservati ance nel caso di chiamate a sottoprogrammi che non utilizzino il modulo.
Per utilizzare un modulo, ciascun sottoprogramma che ne ha
bisogno, dovrà avere un' istruzione
USE nome_modulo
Come prima istruzione subito dopo il nome del sottoprogramma stesso.
L' istruzione USE rende dunque visibili nella procedura che
utilizza il modulo tuti i nomi pubblici dello stesso. Eventualmente si
può utilizzare solo alcune delle entità
del modulo attraverso il meccanismo del parametro ONLY
nell' istruzione USE. Ad esempio, con
USE nome_modulo, ONLY:n1,n2,n3
si rendono visibili nel programma che usa il modulo solo le
entità (variabili, tipi dati, sottoprogrammi)
di nome n1,n2,n3, indipendentemente dall' esistenza di altre
entità pubbliche.
E' anche possibile che all' interno del programma che
utilizza il modulo, alcune entità del modulo siano
ribattezzate con un nome diverso. Per esempio, per usare un
modulo e far sì che la variabile del modulo di nome
var_mod sia indicata nel
programma come var_prog,
basta
usare l' istruzione nel seguente modo:
USE nome_modulo, var_prog => var_mod
Un modulo può usare un altro modulo (ma non e' consentita ricorsione).
All' interno del modulo possono essere definite interfacce generiche o
interfacce che definiscono nuovi operatori e/o estendono operatori
esistenti. Nelle interfacce di questo tipo, i riferimenti alle
funzioni del modulo vanno fatti mediante l'
istruzione
MODULE PROCEDURE nome_funzione
Si possono anche aggiungere funzioni intrinseche ad un' interfaccia
mediante l' istruzione
INTRINSIC FUNCTION nome_funzione_intrinseca