Newsgroup: it.comp.lang.visual-basic
Titolo: [?]Qualita' di ByRef e ByVal

Tutti (o quasi :p) sappiamo la differenza fra ByRef (di default in VB) e
ByVal.
Riassumo, in ogni caso:
- ByRef passa il parametro per riferimento, per cui il parametro della
funzione e' a tutti gli effetti la variabile passata. Questo significa
che se il parametro viene modificato, viene modificata anche la
variabile.
- ByVal passa il parametro per valore, per cui il parametro della
funzione e' una copia della variabile passata, ovvero una nuova
variabile in cui e' copiato il valore della variabile passata.
Ai fini di una corretta progettazione delle routine, i parametri che
_non devono_ essere modificati dovrebbero essere passati per valore,
indipendentemente dal fatto che la routine li modifichi o meno.
Se i parametri passati per valore sono a tutti gli effetti variabili
dello stesso tipo di quella passata, mentre quelli passati per
riferimento sono in qualche modo dei puntatori alla variabile di quel
tipo, in entrambi i casi si ha una copia di un valore da una variabile
ad un'altra (nel primo caso il valore della variabile, nel secondo il
suo indirizzo). Quindi lo spazio occupato dal parametro, e le operazioni
effettuate all'attivazione della funzione sono le medesime.
L'unica differenza che riesco ad immaginare (ma potrebbe essere una
castroneria) e' che i parametri ByVal "occupano" lo spazio del tipo (4
Byte per un Integer ad esempio) mentre quelli ByRef essendo
fondamentalmente dei puntatori occupano sempre lo spazio di un'indirizzo
(8 Byte?).
Ho imparato "per sentito dire" che mettere un parametro ByVal e'
"meglio" in VB, ma non riesco a capire (al di la' della buona
progettazione e del viaggio mentale che mi son fatto nel precedente
paragrafo) il perche'.
Qualcuno e' in grado di dare delucidazioni sull'argomento?
Lokar
--
Sito Comune: 
http://www.it-lang-vb.net/
Manifesto: 
http://www.it-lang-vb.net/docs/Manifesto.txt

 paragrafo) il perche'.
non esiste in questo caso il "meglio" in quanto dipende da cosa devi fare...
ciao

 dipende da cosa devi fare...
Mi pare che le premesse fossero sufficienti. Ci riprovo.
Nel caso in cui possa tranquillamente scegliere fra ByRef e ByVal per il
passaggio di un parametro, senza che questo infici il funzionamento
della funzione stessa (ad es. in funzioni che aprono un file in lettura,
passato il nome come parametro stringa), perche' ByVal e' meglio, al di
la' della "buona progettazione"? E' quest'ultima l'unico motivo?


 wrote in message
LfSW8.14$IC6...@nreader1.kpnqwest.net...cut
( OT:
scusate la R ma OE non vuole sapere di aggiornarsi e fallisce  miseramente)
Cito Balena dal libercolo che era insieme a pc professionale:
"
........
Un argomento puņ essere passato per valore ByVal o per riferimento (Byref o
omettendo il qualificatore).
Gli argomenti passati per riferimento possono essere modificati dalla
routine chiamante ed il valore modificato puņ essere riletto dal chiamante,
mentre le modifiche apportate agli argomenti passati per valore non vengono
MAI propagate al chiamante.
La regola che consiglio di rispettare č passare sempre per riferimento gli
argomenti che devono essere modificati dalla routine e passare per valore
tutti gli altri argomenti.
Questo approccio riduce il rischio di modificare accidentalmente il valore
di una variabile passata al metodo.....etc etc..."
...mi sembra abbastanza chiaro....
:-)

 la' della "buona progettazione"? E' quest'ultima l'unico motivo?
Ovvio che se non è influente, passarlo per valore non potrà in alcun modo
modificare la "tua" stringa ,perciò sicuramente sarà la cosa giusta da fare
:))
ciao


Premessa: in VB la gestione dei parametri è pietosa.
Dovrebbe esserci la possibilità di definire i parametri Static ByRef, in
modo da poter passare il puntatore ma non lasciar modificare il dato e ByVal
anche strutture e array.
Comunque è il contrario di quanto dici:
- ByRef viene passato l'indirizzo (4 byte)
- ByVal viene passato il dato (una copia) quindi più o Len(dato) (Len(dato)
* 2 nel caso di stringhe).
Per questo non mi piace passare ByVal le stringhe, anche se sarebbe buona
norma farlo: se la stringa è lunga si sovraccarica lo stack e si
appesantisce la cpu (dovrebbe anche essere più lento).
Ciao

 appesantisce la cpu (dovrebbe anche essere più lento).
c'è il rallentamento nel caricare tutta la stringa nello stack ma non
nell'uso in quanto è semrpe una gestione della memoria . Il rilascio (Se il
codice è fatto come dovrebbe) il tempo di esecuzione non varia di molto in
quanto e solo un'istruzione di incremento del puntatore per lo stack
(ricordiamoci che funziona al contrario).
ciao

 :-)
In pratica conferma la mia ipotesi che sia solo una questione di "buona
progettazione". Che mi dici della "pesantezza" dei due?


 wrote in message
H2TW8.17$tY2...@nreader2.kpnqwest.net...
CUT...
se hai una decina di routine ...si!
se il progetto è complesso... a" più mani" etc etc...se una routine chiama
un altra a cascata...etc etc...
beh la possibiltà che una variabile non sia modificabile da distrazioni ed
errori in altre routine...mi senbra un ottimo motivo!
ricordiamoci che siamo sempre esseri umani.....ci distraiamo facilmente...e
meno occasioni di sbaglaire abbiamo...meglio è! (vedi ho appena fatto un
errore!)
...esempio stupido...
pensa se hai una stringa che contiene il path di un archivio e nel passare
una serie di valori ad una routine...che controlla se il file esiste ...per
un errore di programmazione o una svista... questa te lo modifica...succede
un macello!
..............
ma anche se hai 2 sole routine.....
..........
Balena  da anche una sua versione ulteriore dell'utilità
a ri -cito
" la dichiarazione di un parametro usanfo ByVal presenta un altro vantaggio:
è possibile chiamare la routine passando una variabile o una espressione di
questo tipo e lasciare che VB si occupi della conversione del tipo di dati;
se invece un parametro viene dichiarato ByRef e passate una variabile, i
tipi devono corrispondere"
esempio del libro (pag 148)
' Se x,y,z NON sono long ad esempio single o double
DrawPoint  x , y , 100 ' Correttamente eseguito
DrawPoint x , y , z ' Non funziona (tipo non corrispondente per ByRef)
.."
DrawPoint è:
'Z erroneamente definito ByRef
Sub DrawPoint(ByVal X as Long, ByVal, Y as Long, Z as Long)
if X<0 THEN x=0
if y<0 then y=0
if z<0 then z=0 ' possibile fonte di bug!!!
.....
End sub
La routine si auto aggiusta i parametri ma sarebbe sbagliato modificare i
dati di chiamata (o potrebbe essere fonte di problemi logici difficilmente
tracciabili....credevi di avere dei valori dei parametri ed a un certo punto
ne trovi altri!)
e + sotto dice in sintesi
unica eccezione se dichiari logicamente ByRef Variant   va beh allora puoi
utilizzare qualsiasi cosa!!
e più sotto ancora parla di usare ByVal per gli Alias di una funzione che
impediscono al compilatore di ottimizzare...etc etc.........ma non è più
semplice se trovi il libro dal tuo edicolante????

 appesantisce la cpu (dovrebbe anche essere più lento).
Sulle stringhe immaginavo ed ovviamente concordo.
Cosa succede nel ByVal per gli Integer o nei Boolean? 2 byte contro i 4
byte del ByRef (quindi meglio ByVal)?
Sono corrette le seguenti supposizioni?
- Piu' efficente ByVal per i tipi di dati <= 4 byte
- Piu' efficente ByRef per i tipi di dati > 4 byte
Attendo anche commenti di H.P.L. sulla questione. ;)
Happy Coding =)


 edicolante????
ROTFL! Forse si, piu' tardi faccio un salto =)
Personalmente sono del parere che se uno si "scorda" di mettere ByVal in
qualche funzione dove invece andava messo e' appunto un errore del
programmatore e si merita il bug <gg>.
In ogni caso, non e' che se lo dice Balena e' oro colato...  Soprattutto
se il fatto di mettere un parametro ByRef piuttosto che ByVal, porta a
delle ottimizzazioni che in larga scala diventano discrete.
Immagina ad esempio di caricare di seguito piu' file di testo da 50K
l'uno in una stringa e poi passare la stringa ad una funzione che ne fa
il parsing. E' evidente che passando tale stringa con ByVal hai un
dispendio di memoria doppio (o triplo? appena Zanna risponde all'altro
thread... ;)), per non parlare dell'uso della CPU per
allocazione/deallocazione.
Ho aperto il thread per fare giustappunto una disquisizione di questo
tipo, nelle premesse era ben chiaro che volevo tralasciare "l'uso di
ByVal per buona programmazione" - leggi "ByVal per evitare cappelle del
programmatore distratto".


 - Piu' efficente ByRef per i tipi di dati > 4 byte
In linea teorica si, ma da un punto di vista pratico la differenza sui tipi
di dato "normali" e' assolutamente trascurabile.
L'unico caso reale in cui ByRef puo' portare ad un apprezzabile incremento
di prestazioni e' appunto quello di variabili stringa particolarmente grosse
(diciamo nell'ordine dei Kb, non dei byte) con chiamate ricorrenti alla
funzione.
Personalmente ti consiglierei di non "limare il byte" ma trattare i tuoi
parametri nella forma piu' naturale, usando ByRef solo quando intendi usare
il parametro in output oppure in casi effettivamente delicati come quello
appena detto; oltre alle inevitabili distrazioni di cui parlava Wodka, un
criterio di questo tipo fa si che le funzioni si commentino in parte da
sole, viceversa costringi te stesso, o peggio chi lavora con te, ad essere
sempre in dubbio e a chiedersi se quel tale ByRef e' da considerare "reale"
o un ottimizzazione
Ciao
--
Luca Dormio - 
luca....@tin.it
________________________________
"Marty, non stai ragionando in maniera quadridimensionale"
Dr. Emmett L. Brown

 In linea teorica si, ma da un punto di vista pratico la differenza sui
tipi
ma in pratica no, nello stack avvinene cmq un push di 4 byte nelle chiamate
stdcall anche se i parametri sono minori di 4 byte ..
ciao

 stdcall anche se i parametri sono minori di 4 byte ..
Giusto! =)
Grazie per aver fornito un valido motivo per cui la supposizione risulta
errata.
Pertanto (nuova supposizione):
- Stessa efficenza tra ByVal e ByRef per i tipi di dati = 4 Byte
- Piu' efficente ByRef per i tipi di dati > 4 Byte
E' quindi giusto presumere che funzioni che accettano parametri Double,
Date o addirittura Variant siano piu' "efficenti" con un passaggio
ByRef?
Il tutto sempre omettendo le regole di buona programmazione.


 ByVal e' "meglio" in VB
ed infatti cosi' faccio. Ma ogni volta che scrivo ByVal mi e'
inevitabile pensare che sto usando il modo meno efficente.
Voglio fugarmi ogni dubbio =)
Mi capita spesso di dover scrivere applicazioni C/C++ in cui la
velocita' di esecuzione e' critica e sto li' a limare ogni virgola. E
poiche', altresi' in VB, lavoro ogni giorno con moli immense di dati
(tipicamente stringhe e/o double) desidero conoscere a fondo le
limitazioni e le qualita' dello strumento che uso (VB per inciso).
In ogni caso, non tralascerei mai di segnalare l'ottimizzazione, dato
che il mio codice e' sempre ben commentato... come quello di tutti qui,
no? <gg>


 Il tutto sempre omettendo le regole di buona programmazione.
ormai ci siamo dilungati e l'efficienza ha un significato diverso cmq...
se intendi il risparmio di memoria č ovvio che il byref limita lo spreco....
se intendi il passaggio di un semplice long č chiaro che il byval č piů
sicuro...
Per gli oggetti si fa complessa la cosa ... io non consiglierei di passare
oggetti che allocano memoria dinamicamente tramite byval, potrebbero (come
gia spiegato) causare casini di deallocazione.
ciao

 nell'uso in quanto è semrpe una gestione della memoria .
Chiaro, ma immagina una funzione ricorsiva su una stringa da 500k passata
byval: 10 ricorsioni e ti sei fregato 10M di ram anzichè 500k, tenendo
sempre presente che una stringa da 500k è in realtà da 250k di char.
Tu dirai: chi è che ha bisogno di stringhe tanto lunghe?
Lo diceva anche bill con i PC con ram da 640k :)
Ciao

 Tu dirai: chi è che ha bisogno di stringhe tanto lunghe?
con le stringhe che uso io ti potrei dire così corte? :)))
ciao :)

Qualcuno mi sa dire che differenza c'č fra passare un oggetto ByVal o ByRef
?
es:
Sub MiaFunzione(ByVal obj As Object)
oppure
Sub MiaFunzione(ByRef obj As Object)

 Perche' *2 nel caso delle stringhe?
Perchè in VB le stringhe sono unicode.
Ciao

  "quindi Len(dato) (Len(dato)*2 nel caso di stringhe)"
+ 2(?) byte di descrittore per ogni stringa.
Ciao

 modificare il dato e ByVal anche strutture e array.
più che Static, Const. La differenza è importante. Static, stando alle 
convenzioni del C/C++, significherebbe che il parametro è una variabile 
globale. Intendiamoci: globale non nel senso di visibilità all'interno 
del codice, globale nel senso che è situata nel .data dell'eseguibile, 
e quindi tutti i thread del processo per quella variabile vedranno lo 
stesso valore; e non solo, lo stesso thread, in punti diversi di 
esecuzione, vedrebbe sempre lo stesso valore. Un parametro Static, tra 
le altre cose, renderebbe macchinosetta la ricorsione (pensaci)
Comunque, ci sto lavorando :-) Sto progettando, più o meno seriamente e 
da qualche anno, un compilatore VB decente, che permetta questo ed 
altro (ad esempio dichiarare variabili As RefTo <tipo>, ossia puntatori 
tipizzati). Non sono mai andata oltre un abbozzo di lexer, però ;-(
-- 
 < 
http://www.reactos.com/
 >  Open source clone of Windows NT. Current
     Don't stand, REACT!      version 0.0.19. C, C++ and ASM developers
                              and beta testers are welcome!

 da 250k di char. 
10 MB sullo stack non ci stanno nemmeno :-) Lo stack tipico in Windows 
dovrebbero essere 4 MB riservati, successivamente allocati a blocchi di 
una pagina alla volta


 "buona progettazione". Che mi dici della "pesantezza" dei due?
finchč si tratta di roba che sta in un registro di CPU (Byte, Integer, 
Long, Object, etc.), un ByVal č un'istruzione [1], totale 2-5 cicli di 
clock [2], mentre un ByRef sono due, per un totale di 4 cicli [3]. 
Quando mettiamo in campo cose piů pesanti come String, Type, Variant, 
ecc. un ByVal sono (LenB(parametro) / 4) istruzioni, mentre un ByRef 
continua ad essere due istruzioni, qualsiasi sia la dimensione dei dati
[1] per la precisione, ByVal č un PUSH, ByRef un LEA seguito da un PUSH
[2] 2 se la variabile era in un registro (conoscendo il compilatonto di
    VB, dubito), 5 altrimenti
[3] 2 per il LEA,e  2 per il PUSH, dato che l'indirizzo ricavato con il
    LEA viene sempre salvato in un registro


 son fatto nel precedente paragrafo) il perche'.
Beh, mi pare che "la buona progettazione" sia un più che
valido motivo.
Primo perché eviti ogni possibilità di modificare per errore
il parametro passato, secondo perché leggendo il codice
comprendi se la funzione modificherà il parametro o meno,
senza leggere il codice della funzione stessa.
Ciao.
--
BSD is for UNIX-lovers -- linux is for Windows-haters.

 Attendo anche commenti di H.P.L. sulla questione. ;)
Ti rimando ad un mio post precedente sulla questione, nel
quale discutevo, guarda caso ;-), con Zanna, da sempre
sostenitore del passaggio dellle stringhe ByRef (cosa che,
come sarà chiaro, non mi trova per nulla d'accordo):
http://groups.google.com/groups?ie=ISO-8859-1&as_umsgid=zgx98
.
54873%243J1....@news2.tin.it
&lr=&hl=it
Nel suddetto post *non* ho avuto problemi a passare ByVal (con
perdite di prestazioni veramente limitate rispetto a ByRef)
una stringa di 190 MB... traine tu le adeguate conclusioni...
Comunque voglio ricordare che le ottimizzazioni premature
sono, oltre che inutili, molto spesso dannose...


 piů che Static, Const. La differenza č importante.
Sě, hai ragione, non so perchč mi č scappato Static.
Intendevo dire proprio Const.
Ciao