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:
  1. i moduli comportano la costruzione dell'  interfaccia da parte del compilatore,  semplificando il compito del programmatore;
  2. 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;
  3. i moduli permettono un migliore controllo sull'  accessibilità,   eventualmente parziale,  di più  sottoprogrammi tra loro collegati,  migliorando  la moduarità  del codice;
  4. 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