Newsgroup: it.comp.lang.delphi
Titolo: Variabili Globali

Ciao a tutti, toglietemi una curiosità, perchè bisognerebbe NON usare
variabili globali? Solitamente nel mio prog possono essercene da 5 a magari
20. Sono troppe?
Trovo molti vantaggi ad usarle globali...
1. Inizializzazzione diretta        Es: i : Integer = 0;
2. Lettura/Scrittura nella varie procedure
3. Comodità per tener conto di vari indice in array (code, ecc...)
Perchè non bisognerebbe usarle? Spreco di memoria?
Ps:- Inoltre sono visibili anche nelle altre Unit del programma

 Ps:- Inoltre sono visibili anche nelle altre Unit del programma
Questo dipende da dove le dichiari (se nella sezione interface o
implementation).
Ciao
--
Andrea /\/\agni
ICQ#: 174108000

 variabili globali?
Era un problema dei vecchi linguaggi di programmazione,
proprio per questo e nato lo "scopo" delle variabili.
Ricordo il titolare di una ditta in cui lavoravo e le sue
variabili globali (cobol e clipper) specie per i cicli
cominciavano con "oi" poi "ooi" poi "oooi" e cosi' via
uno spasso. Quando nonti tornavalo le cose c'era da
impazzire per capire quale azz di oooooo era sbagliata.
Ciao!
Marco Kregar
marco....@firebirdsql.it
www.firebirdsql.it


Ciao,
premetto che provengo dal "mondo clipper" e che di variabili globali ne ho
sempre usate tante (imparando a starci attento quando le creavo).
Non ho nessuna conoscenza di pascal e solo da un paio di anni creo programmi
con Delphi 5 pro utilizzando quelle che sono le mie conoscenze di 13 anni di
clipper alle spalle.
Uso regolarmente, e di sicuro erroneamente (visto quanto affermate), un
numero molto alto di variabili globali. Le inserisco nella unit principale e
poi le uso in tutte le unit da essa richiamate non notando alcun problema,
ma evidentemente i problemi ci sono (visto sempre quanto affermate).
Se nella unit principale inizializzo una variabile e poi richiamando
un'altra unit utilizzo la stessa variabile per far fare alle varie procedure
determinate cose, come dovrei fare per passare questo parametro senza
utilizzare una "variabile globale" ?
Esempio
La unit A inizializza la variabile FLAG come integer, la inizializza (a 0 o
a 1) e poi richiama la unit B (che tra le uses ha la unit A)
La unit B se trova FLAG = a 0 fa una cosa e se la trova = a 1 ne fa
un'altra.
Se non definisco FLAG come variabile globale come dovrei fare a farla vedere
alla unit B ?
Io sono un'autodidatta e uso Delphi per lavoro, non ho fatto nessun corso e
ho letto pochi manuali. Lavoro in pratica imparando di volta in volta ed in
questi due anni di cose ne ho capite spero molte, ma questa proprio no !
Chiedo quindi cosa significhi "... variabile globale "di classe" ...". Basta
un esempio di come applicare questo concetto.
Ciao e grazie per l'attenzione.
Marco
-- 
MaoSw
Reporter Professional srl
supporto...@reporterprofessional.it

 
Appunto, e questo ti pare un vantaggio? Hai presente cosa vuol dire 
perdere ore o giorni a debuggare un software per poi scoprire che una 
dannata variabile globale era modificata in un punto dove non avrebbe 
dovuto essere (perche' magari ha un nome simile ad una variabile 
locale), oppure e' modificata concorrentemente da piu' thread? Un vero 
inferno!
Comunque, PERCHE' NON BISOGNEREBBE USARE LE VARIABILI GLOBALI:
- perche' sono segnali di un cattivo (pessimo) design del software, e di 
una architettura che non sta' in piedi o avra' molto probabilmente 
problemi tra una settimana o poco piu'.
- perche' aumenta le dipendenze tra moduli (unit). questo e' un problema 
se vuoi riutilizzare dei moduli in varie applicazioni (e la 
riutilizzabilita' del codice ti permette di ridurre i tempi di sviluppo).
- perche' non ti danno nessun meccanismo per controllarne l'accesso e/o 
la scrittura di un valore non valido. Piccolo esempio: hai una variabile 
globale che memorizza un valore percentuale, range valido [0..100], ma 
e' di tipo smallint (esempio del cavolo, ma spero si capisca il 
concetto). Chi ti assicura che da qualche parte nel codice, per vari 
motivi (distrazione, specifiche modificate, bug, ...) questa variabile 
non venga impostata ad un valore non valido? Quanto tempo mediamente ci 
metterai a capire che il programma non funziona correttamente per quel 
motivo? Se il programma e' di dimensioni medio/grandi... tanto, tanto tempo!
- perche', visto che e' globale, puo' essere modificata o letta da 
thread diversi... chi ti assicura che non ci siano race condition e il 
valore sia consistente se letto da un thread mentre viene modificato da 
un altro?
- perche' spesso una variabile globale tende a non bastare da sola, e 
allora ecco che le variabili di "appoggio" diventano globali anch'esse, 
e via cosi', fino a far diventare il codice una schifezza.
- perche' se devi fare dei controlli sul valore di quella variabile, 
dove metti il codice di controllo? In tutti i posti dove serve, facendo 
cosi' prolificare il numero di righe di codice uguale o molto simile, 
rendendo cosi' la manutenzione futura un incubo per generazioni di 
programmatori Delphi? No, no, cosi' non si fa :-)
Frunktz, forse non hai molta esperienza nel campo della programmazione 
(altrimenti, spero, non ti saresti nemmeno posto questa domanda), ma se 
questo e' il tuo lavoro (o anche solo un hobby a cui tieni), con il 
tempo l'esperienza ti dira' che le variabili globali possono spesso 
rappresentare un problema per questi e altri motivi, per cui e' logico 
evitarne l'uso o almeno ridurlo il piu' possibile.
La comodita' di scrivere una riga di codice in meno, o di far rifeimento 
alla stessa variabile da piu' funzioni o form, e' solo cio' che puoi 
vedere superficialmente. Al momento, magari, non vedi i problemi o i 
pericoli che queste _piccole_ comodita' nascondono.
-- 
Roal Zanazzi

> Perchè non bisognerebbe usarle? Spreco di memoria?
a mio parere, l'uso di variabili globali e' ammissibile solo in casi
particolari, ad esempio per rendere accessibile a tutto il programma lo
stato di una certa operazione che puo' essere fatta da piu' parti del
programma, e sempre che le procedure non girino in multithread, altrimenti
bisognerebbe comunque incorporare le variabili globali in "sezioni critiche"
specifiche per il thread che si sta trattando.
Nella programmazione OO, i messaggi tra una classe ed un'altra vanno gestiti
tramite proprieta' ed eventi, non tramite riferimenti a variabili esterne
condivise dalle classi. E' un livello di astrazione che semplifica il debug,
al prezzo di complicare e allungare il codice. E' quindi una scelta
personale usare le variabili globali o lo stile OO. Delphi consente entrambi
gli approcci, per fortuna :)
Ciao, Sandro

 Delphi consente entrambi gli approcci, per fortuna :)
Delphi consente entrambi gli approcci, PURTROPPO.
poi, quando ti trovi a mettere le mani in roba fatta da altri che PURTROPPO
usano questa possibilità, tiri giu il paradiso....
Ma in fondo, la colpa non è degl strumenti ma di chi li usa.....
Bye
A

> Ma in fondo, la colpa non è degl strumenti ma di chi li usa.....
esatto :)
Quando sul programma bisogna metterci le mani in tanti, comunque, e'
opportuno stabilire delle regole A PRIORI, altrimenti le cose effettivamente
possono diventare molto complicate, e i costi salire di conseguenza.
Ciao, Sandro

Zortek wrote:

Il problema spesso non e' solo che ad un progetto partecipano piu' 
sviluppatori contemporaneamente, ma anche che vi partecipino in tempi 
diversi, magari nell'arco di qualche anno. In questo caso e' difficile 
stabilire regole a priori, o e' difficile forzare quelle regole sugli 
sviluppatori futuri.
Con i "project manager software specialist super mega evangelist" che ci 
sono in giro di questi tempi, poi... :°-(
-- 
Roal Zanazzi

 
Per il concetto di "classe" ti rimando all'help di Delphi, credo ci sia 
scritto da qualche pate un'introduzione alla programmazione ad oggetti.
Per "variabile globale di classe" non capisco bene cosa tu intendi (?)
-- 
Roal Zanazzi

 ...". Basta un esempio di come applicare questo concetto.
In realtà quando l'ho scritto per un attimo pensavo che in Delphi esistesse
un analogo degli attributi statici di Java. In pratica si tratta di un
membro di una classe che invece di essere associato ad un'istanza di quella
classe è unico per tutte le istanze e viene condiviso.
In Delphi non c'è ma si può simulare agevolemente con un metodo di classe e
una variabile globale (da mettere nella sezione implementation!):
class TPippo=class
 public
  class function GetVariabile:string;
end;
implementation
var
  _Variabile: string;
function TPippo.GetVariabile: string;
begin
  result := _Variabile;
end;
Ciao :-)


Grazie ad emtrambi.
Ora č tutto un poco piů chiaro.
Troppi anni a creare "variabili", mi hanno condizionato.
Inizierň a mettere in pratica questi consigli perchč in effetti a volte
perdo delle ore a capire pechč qualcosa non funziona e poi č "solo" una
"maledetta" variabile che ha un valore diverso da quello che dovrebbe.
Grazie ancora.
Ciao


 una variabile globale (da mettere nella sezione implementation!):
c@@@o!
Non ci avevo mai pensato!
Mi stavo dannando l'anima sulle possibili soluzioni di questa limitazione..
Giusto!Giusto!
Leggevo il libro sui design patterns, in particolare il singleton e pensavo
"Grande, ma in delphi come lo fai???"
Per la cronaca, io ho usato:
DOS
gwbasic
quickbasic 4
quickbasic 4.5
microsoft basic 7.1
clipper 5.2
turbo pascal 5.5
WIN
Vb5/6
Delphi 4/5
Ho mollato le variabili globali prorpio quando sono approdato a clipper e
turbo pascal.
Bye e high(TERAInt) grazie per quella supenda ed elegante dritta sul
singleton.
A

 alla unit B ?
In primis, meglio eviate i numeri cabalistici.
Domani avrai gia dimenticato il significato di 1,2 3, ..n per indicare uno
stato.
meglio usare un tipo enumerato.
Type TMiaOperazioneInCreazione = (moicApriForm1, moicAzzeracaption,
moicQualcosaltro);
modo 1:
Se unit1 e unit2 sono dei form/data mdoule, nella sezione public ci metti
'sta cose:
property Flag: TMioTipo read FFlag write SetFlag;
poi, nella OnCreate del moudlo:
case Flag of
  MioTipoValore1: TMiaOperazioneIncreazione;
  MioTipoValore2: faistaltracosa
  MioTipoValore3: nonfareunca##o
end;
Questa modo è il + semplice ma pone una serie di problemi.
Io, personalmente uso questa tecnica:
a) dichiaro un tipo record, TCreationInfo:
type TCreationInfo = record
   valoreCheServe1: integer;
   ValoreCheServr2: integer
   ValoreCheServe: qualcosalto
end;
nel form o data module che sia creo un MIO costruttore, dichiarandolo magari
+ colte con param diversi usando la direttiva di overload;
protected
procedure ProcessCreationInfo(AInfo: tCreationInfo); VIRTUAL;
public
  constructor MyConstructor(AOwner: TComponent; AInfo: TCreationInfo);
overload;
  constructor MyConstructor(AInfo: TCreationInfo); overload;
constructor TMioForm.MyConstructor(AOwner: TComponent; AInfo:
TCreationInfo);
begin
  inherited Create(AOwner);
  FCreationInfo := AInfo;
  ProcessCreationInfo(AInfo);
end;
constructor TMioForm.MyConstructor(AInfo: TCreationInfo);
begin
  MyConstructor(nil, AInfo);
end;
procedure TMioForm.ProcessCreationInfo(AInfo: tCreationInfo);
begin
....
end;
In questo modo hai una serie di vantaggi:
1) se ti serve un qualcosa in +, basta camvbiare il tipo record senza
cambiare i prototipi
2) puoi scambiare il tipo record con una classe senza troppi problemi
3) usando un costruttore definito da te eviti il classico problema delle
operazioni che non possono essere fatte nella OnCreate
Lo svantaggio è il non usare il costruttore predefinito
Adesso tu ti chiedi: xche hia dichiarato la ProcessCreationInfo come
virtual?
Semplice: io in genere ho una form "base" da cui ereditano tutte le form del
progetto.
In questo modo, ogni form che eredita da formbase puo gestire a modo proprio
il trattamento delle informazioni di creazione.
Inoltre, se un bel giorno, tutti i form della tua app necessitano di una
property, basta metterla in form base e senza cambiare altro, tutti i forms
che erditano da esso si ritrovano la sudetta property.
Niente male, no? ;P
A


No, ma come avrai capito non è che i corsi di aggiornamento o i nuovi
SoftWare siano all'ordine del giorno nella azienda in cui sono assunto.
D'altra parte a Cremona non c'è tanto di meglio.
Ciao


 singleton.
Ad onor del vero devo dire che non è farina del mio sacco: me l'ha mostrato 
Nando Dessena proprio per implementare un singleton.
I complimenti quindi vanno a lui :-)


Già, per adesso non lavoro, eh eh ancora a scuola. Come tutti saprete
solitamente nella classi a scuola si va avanti molto molto a rilento, gente
che deve ancora capire la differenza tra procedura e funzione ecc...
Ovviamente tutto nella norma, perchè hanno altro da fare. Poi ogni tanto
escono gruppi di ragazzi, nel mio caso io ed altri miei amici, che vogliamo
andare avanti un qlc in più, quindi il TP non serve più e si passa a Delphi,
e si cerca di imparare vedendo quello che scrivono gli altri, leggere in
giro su internet, copiare il codice di un programma e vedere come lavora,
studiarlo per bene, poi provare a riutilazzarlo scrivendolo INTERAMENTE da
SOLI, in modo da capire il funzionamento. Credo che mi metterò ad
approfondire il discorso sull'OOP, di cui attualmente non sfrutto per
niente... Inoltre credo che mettersi a studiare solo l'OOP e basta sia un
errore in quanto sul lavoro non si può usare solo Delphi o Java o altro,
specie se piccole, ma si tende ad utilizzare linguaggi come VB, che non mi
sembrano OO, anche se alcuni miei compagni dicono che esistano manuali da
600 + pagine dal titolo "Programmazione ad Oggetti in VB6" ...
Cmq tornando all'esempio delle variabili globali, fino ad ora non ho trovato
una soluzione al mio prob... Ad esempio volendo tener conto di una coda(al
momento sto realizzando un f-serve per IRC), sto tenendo conto dell'indice
dell'array, con una variabile globale (indice_q), che incremento o
decremento all'incremento o decremento di queue. Come potrei fare se non
usando una variabile globale??? Realizzare una funzione? In ogni caso però
dovro passagli l'indice della coda...
Cmq grazie a tutti delle risposte.

 
Ehm, non ho capito molto (e non ho mai usato IRC, quindi non ho ben 
presente il concetto).
Comunque una coda in OOP e' una classe in genere appartenente ad un 
gruppo denominato "container" perche' contengono oggetti (in C++ ad 
esempio ci sono varie classi container predefinite dallo standard), e 
tutto cio' che serve per il funzionamento e per mantenere lo stato 
interno della coda e', appunto, interno a quella classe. Se qualcuno 
deve modificare lo stato interno della coda (il suo "indice"), lo 
dovrebbe chiedere alla coda, non credi?
Se non ho capito male usi un array come storage per la coda (scelta 
discutibile, ma dipende da quello che ti serve), quindi anche l'array 
dovrebbe essere interno nella classe coda...
-- 
Roal Zanazzi

 globale???
Se hai fatto le cose per bene dovresti avere una classe TCoda che avrà una
proprietà (magari in sola lettura) "PosizioneCorrente" e dei metodi Add,
Process, Remove ecc ecc...
La tua istanza di TCoda avrà pur un owner o qualcosa cui è riferita... (non
so bene cosa sia un "f-serve" ma dovresti avere un oggetto "principale" cui
agganciare la coda...)
Ciao


 ha scritto nel messaggio
news:fn41b.117749$cl3.3...@news2.tin.it...


 (PS:- è consigliabile usare un record in un record ???)
Se vuoi scrivere qualcosa di OO dovresti indirizzarti verso una classe
TCoda=class
  private
    FCurrent: integer;
    FLista: TListaDownloads;
  public
    procedure Next;
    procedure Add(...);
    (...)
    property Current: TDownloadInfo read GetCurrent;
    property Count: integer read GetCount;
end;
e TListaDownload potrebbe usare internamente una TObjectList e un altro
container [c'è anche una TQueue che potresti usare (magari ricoprendola e
non derivandone)].
Temo che cmq tutto questo non ti possa essere chiarissimo se non conosci
almeno un po' di OO... alcuni concetti richiedono un po' di tempo/prove per
essere assimilati in pieno.
Dacci dentro! :-)


 ha scritto nel messaggio
news:0561b.118226$cl3.3...@news2.tin.it...


quello che serve è anche un cambio di paradigma: pensare a oggetti.
A

 
Il problema di fondo nell'imparare la programmazione ad oggetti non e' 
tanto il "come scrivere codice", ma come "pensare ed organizzare il 
software _ad oggetti_".
In molti casi per chi viene dalla programmazione strutturata lo scoglio 
iniziale e' proprio il non capire che deve _cambiare il modo di pensare_.
In poche parole (che non sono certo sufficienti a spiegare cio' che 
altri hanno scritto in libri interi):
programmazione strutturata:
- alla base c'e' il dato, magari raggruppato in strutture.
- il dato deve essere manipolato in qualche modo, per questo vengono 
usate delle funzioni.
- dati e funzioni sono spesso pensati come slegati, per cui salta fuori 
la necessita' di avere i dati come globali, in modo da poterli 
modificare da piu' funzioni. E questo e' forse quello che succede a te.
programmazione ad oggetti:
- il dato da solo non serve (ce ne siamo gia' accorti sopra, no?)
- il dato ha bisogno di funzioni, e allora perche' non mettere insieme 
dati e fuznioni? -> nascono le classi.
- le classi sono "modelli" di oggetti.
classe e' l'automobile (da cui puoi creare oggetti "Fiat 500", "VW 
Golf", "Ford Focus", ...), o la persona, o l'animale, ...
Le classi (e gli oggetti che ne sono la loro concretizzazione), vivono 
di vita propria, hanno internamente i dati che le caratterizzano (il 
modello e il costruttore per l'automobile, il nome e l'eta' per la 
persona, etc...) ma forniscono anche le funzioni per far conoscere 
all'esterno o modificare il loro stato interno, per interagire con altre 
classi, etc...
Il mio consiglio e': non mollare, prenditi un buon libro o scaricati da 
internet un buon tutorial sulla programmazione ad oggetti e studia, se 
ti piace programmare vedrai che il tempo dedicato allo studio di questi 
argomenti ti sara' prezioso anche per entrare nel mondo del lavoro.
Per inciso, se non erro (qualcuno mi corregga) nel manuale del vecchio 
Borland Turbo Pascal 5.5 c'era un'ottima introduzione alla 
programmazione ad oggetti, forse e' persino recuperabile su internet in 
formato PDF, prova a cercare sul sito 
http://bdn.borland.com
 o cercalo 
con Google.
-- 
Roal Zanazzi