Page 1 of 2 1 2 LastLast
Results 1 to 15 of 18

Thread: Waarom gebruik Delphi soms Value parameters ipv const

  1. #1
    Senior Member Henk Schreij's Avatar
    Join Date
    Sep 2002
    Location
    Heino (Raalte)
    Posts
    1,445

    Waarom gebruik Delphi soms Value parameters ipv const

    Ik ga een beginnerslezing houden over var, const, out en value parameters.
    Kijkend naar wat procedures en functies in Delphi, zie ik dat de parameters meestal netjes als const, var of out zijn gedeclareerd.
    Maar niet altijd.

    Bijv:

    Delphi Code:
    1. function IsLeapYear(Year: Word): Boolean;
    2. function EncodeDate(Year, Month, Day: Word): TDateTime;

    Iemand een idee waarom hier niet gewoon const voor Year e.d. staat?
    Is het gewoon "doet er niet toe" of "slordig". Of is er een echte reden.

    Ik wil het weten omdat beginners soms zulke moeilijke vragen stellen. En dan kom ik er achter dat ik het zelf niet snap.

  2. #2
    John Kuiper
    Join Date
    Apr 2007
    Location
    Almere
    Posts
    6,387
    Ik denk dat het te maken heeft met het gebruik maken van de parameter in de functie. Als const kan dat niet. Dat is de enige reden wat ik daarvoor kan verzinnen.
    Delphi is great. Lazarus is more powerfull

  3. #3
    En ook omdat het geen zin heeft. Const wil volgens mij ook zeggen dat je een referentie mee geeft. Dat je de variabele niet aan kunt passen is iets dat vervolgens door de compiler wordt afgedwongen. var en const liggen dus erg dicht bij elkaar.

    In dit geval geef je een Word van 2 bytes mee. Een const of var parameter zou een referentie, ofwel een pointer van 4 bytes zijn. Het is dus mogelijk efficienter om het op deze manier te doen.

    Overigens geldt ook voor strings dat het niet uitmaakt. Strings in Delphi zijn copy-on-write. Dat wil dus zeggen dat je ook bij een by-value parameter pas een kopie van je string krijgt als je'm gaat wijzigen.
    I know a joke about UDP, but you probably won't get it.

  4. #4
    Senior Member Henk Schreij's Avatar
    Join Date
    Sep 2002
    Location
    Heino (Raalte)
    Posts
    1,445
    @ John. Ja, dat is een logische verklaring.
    Alleen wordt het niet zo gebruikt, zie (in SysUtiles):
    Delphi Code:
    1. function IsLeapYear(Year: Word): Boolean;
    2. begin
    3.   Result := (Year mod 4 = 0) and ((Year mod 100 <> 0) or (Year mod 400 = 0));
    4. end;
    5.  
    6. function EncodeDate(Year, Month, Day: Word): TDateTime;
    7. begin
    8.   if not TryEncodeDate(Year, Month, Day, Result) then
    9.     ConvertError(@SDateEncodeError);
    10. end;
    En ook binnen TryEncodeDate, etc. worden overal netjes hulpvariabelen gebruikt en niet de invoervariabelen.

  5. #5
    John Kuiper
    Join Date
    Apr 2007
    Location
    Almere
    Posts
    6,387
    Als een pointer 4 bytes heeft en een variabele 2, dan lijkt het inderdaad een kwestie van geheugenbeheer te zijn, zoals Goleztrol zegt. Echter vind ik het dan wel vreemd. Ik heb ergens een artikel gelezen (volgens mij was dat Blaize), dat je beter een constante kan gebruiken als parameter. Op het moment dat de compiler dit vertaalt, worden er minder regels in assembly aangemaakt. Welke winst heb je dan? Een kleinere executable, waardoor er meer werkgeheugen overblijft, of een executable met minder werkgeheugen.
    Ik denk dat ik je een antwoord schuldig moet zijn, Henk.
    Delphi is great. Lazarus is more powerfull

  6. #6
    Tja. Het hangt er natuurlijk ook maar net vanaf hoe de compiler dit optimaliseert. Een variabele die in de functie niet gewijzigd wordt kan namelijk alsnog als const meegegeven worden. Als je 'm in de functie wel wijzigt, dan kan het vertaald worden naar een const en een lokale kopie. Daar zitten allerlei slimmigheidjes in.

    Overigens is dit denk ik niet iets om je zorgen om te maken. De hoeveelheid geheugen, noch de hoeveelheid code of de executietijd daarvan zijn niet iets om in dit geval rekening mee te houden. Ik betwijfel ook ten zeerste of het een bewuste keuze is geweest om deze parameters niet const te maken.
    I know a joke about UDP, but you probably won't get it.

  7. #7
    Een const is toch een optionele parameter? In de gegeven voorbeelden lijken die me juist overbodig omdat de functies alle parameters nodig hebben.

  8. #8
    John Kuiper
    Join Date
    Apr 2007
    Location
    Almere
    Posts
    6,387
    En toch kan je een constante meegeven, omdat de waarde van de variabele niet wijzigt. Ik zal het juist gebruiken, omdat ik geen copy van de variabele nodig heb en alleen maar gebruik wil maken van de referentiële waarde.
    Delphi is great. Lazarus is more powerfull

  9. #9
    mov rax,marcov; push rax marcov's Avatar
    Join Date
    Apr 2004
    Location
    Ehv, Nl
    Posts
    8,478
    Goleztrol heeft grotendeels gelijk. In register calling conventies (default op delphi) zal echter toch altijd een geheel register gebruikt worden. Zelfs als dat 64-bit is (of zou worden).

    Stel je een procedure (calling conventie Register) zo voor:

    pascal Code:
    1. function (eax,edx,ecx:integer):integer;
    2. begin
    3.   result:=eax+edx+ecx;
    4. end;

    zal ongeveer 1 op 1 naar assembler worden omgezet, iets als:

    pseudo assembler Code:
    1. push ebx
    2.   ebx:=0;              // ik kan eax niet voor de som gebruiken, er zit al een waarde in.
    3.   ebx:=ebx+eax;
    4.   ebx:=ebx+edx;
    5.   ebx:=ebx+ecx;
    6.   eax:=ebx;
    7.   pop ebx
    8.  
    9. // Een wat slimmere compiler realizeert dat je eax ook als 0+eerste waarde kan zien, en maakt er misschien van
    10.  
    11.   eax:=eax+edx
    12.   eax:=eax+edx

    Echter als het

    pascal Code:
    1. function (const eax,edx,ecx:integer):integer;
    2. begin
    3.   result:=eax+edx+ecx;
    4. end;

    is, dan heb je meer registers nodig omdat je met pointers zit:
    pseudo assembler Code:
    1. var hulp : integer; // op de stack
    2.  
    3.   push ebx
    4.   ebx:=0;    // ik kan eax niet voor de som gebruiken, er zit al een waarde in.
    5.   hulp:=ecx;
    6.   ecx:=eax^;    // [eax]  haal de waarde waar eax naar wijst
    7.   ebx:=ebx+ecx;
    8.   ecx:=edx^;
    9.   ebx:=ebx+ecx;
    10.   eax:=hulp;       // originele waarde uit ecx
    11.   ecx:=eax^;
    12.   ebx:=ebx+ecx;
    13.   pop ebx
    14.  
    15. of in een wat slimmer geval
    16.   push ebx
    17.   ebx:=eax^
    18.   eax:=edx^
    19.   ebx:=ebx+eax
    20.   eax:=ecx^
    21.   ebx:=ebx+eax
    22.   eax:=ebx;
    23.   pop ebx

    Je ziet dat dit beduidend langer is (dit is overigens een vereenvoudiging, sommige processors kunnen de eax:=edx^ en ebx:=ebx+eax in een stap, ebx:=ebx+edx^ dus. De oorzaak hiervoor is, naast de 3 getallen en een tussensom, ook nog de drie originele pointer waarden een tijd bijgehouden moeten worden. Meer ballen in de lucht dus.

  10. #10
    John dat zal best.

    Maar dat soort constantes (een echte "klassieke" constante dus) geef ik niet mee als paramaters. Die definieer ik op een logische plek zoals boven in mijn unit of in een speciale Const unit.

  11. #11
    Senior Member Henk Schreij's Avatar
    Join Date
    Sep 2002
    Location
    Heino (Raalte)
    Posts
    1,445
    @Marcov: Het gaat me behoorlijk boven de pet, nu weet ik ieder geval weer dat ik ook beginner ben
    Maar uit jouw commentaar en dat van GolezTrol begin ik wat te zien.
    Wat voorbeelden:
    Delphi Code:
    1. procedure ShowMessagePos(const Msg: string; X, Y: Integer)
    2. function FindDragTarget(const Pos: TPoint; AllowDisabled: Boolean): TControl
    3. function UpperCase(const S: string): string
    4. function UpCase(Ch: Char): Char
    Overal waar ik string zie komt er const voor (en ook bij andere "zwaardere" typen als bv TPoint, TRect). Maar bij Integer, Word, Byte, Char, PChar, Boolean wordt het er niet voor gezet.

    Ik denk dat het opzettelijk is dat de const wordt weggelaten bij de "lichtere" typen.

  12. #12
    Silly member NGLN's Avatar
    Join Date
    Aug 2004
    Location
    Werkendam
    Posts
    4,744
    Zie ook: enorme strings en pass by reference waarin LL een stukje uit de Delphi Help quote:
    Quote Originally Posted by Lord Larry View Post
    Hieronder volgt een quote uit de Delphi help:
    > Delphi Help > Contents > Delphi Language Guide > Program control > Parameters and function results > Parameter passing
    Variable (var) parameters are always passed by reference, as 32-bit pointers that point to the actual storage location.

    Value and constant (const) parameters are passed by value or by reference, depending on the type and size of the parameter:

    * An ordinal parameter is passed as an 8-bit, 16-bit, 32-bit, or 64-bit value, using the same format as a variable of the corresponding type.
    * A real parameter is always passed on the stack. A Single parameter occupies 4 bytes, and a Double, Comp, or Currency parameter occupies 8 bytes. A Real48 occupies 8 bytes, with the Real48 value stored in the lower 6 bytes. An Extended occupies 12 bytes, with the Extended value stored in the lower 10 bytes.
    * A short-string parameter is passed as a 32-bit pointer to a short string.
    * A long-string or dynamic-array parameter is passed as a 32-bit pointer to the dynamic memory block allocated for the long string. The value nil is passed for an empty long string.
    * A pointer, class, class-reference, or procedure-pointer parameter is passed as a 32-bit pointer.
    * A method pointer is passed on the stack as two 32-bit pointers. The instance pointer is pushed before the method pointer so that the method pointer occupies the lowest address.
    * Under the register and pascal conventions, a variant parameter is passed as a 32-bit pointer to a Variant value.
    * Sets, records, and static arrays of 1, 2, or 4 bytes are passed as 8-bit, 16-bit, and 32-bit values. Larger sets, records, and static arrays are passed as 32-bit pointers to the value. An exception to this rule is that records are always passed directly on the stack under the cdecl, stdcall, and safecall conventions; the size of a record passed this way is rounded upward to the nearest double-word boundary.
    * An open-array parameter is passed as two 32-bit values. The first value is a pointer to the array data, and the second value is one less than the number of elements in the array.
    Const wordt dus afhankelijk van het type By Reference of By Value doorgegeven.
    Het blijkt dus dat wel of geen const slechts verschil uitmaakt voor de programmeur, en niet voor de executable?
    (Sender as TNLDUser).Signature := 'Groeten van Albert';

  13. #13
    Daar zou je weleens gelijk in kunnen hebben
    I know a joke about UDP, but you probably won't get it.

  14. #14
    Silly member NGLN's Avatar
    Join Date
    Aug 2004
    Location
    Werkendam
    Posts
    4,744
    Wel, als we dat even voor waar aannemen, om dan op de originele vraag terug te komen:

    Value parameters i.p.v. const (bij lange parameterlijsten) resulteren wellicht in compactere of leesbaardere code, maar misschien is dat wel een beetje ver gezocht (*). Of het is gewoon een policy van Borland geweest. Of omdat het gewoon geen zin heeft om van sommige parameters const te maken.

    In functies zoals je hierboven hebt aangegeven maakt het dus écht niets uit, maar in virtual methods of in eventmethods maakt het wel degelijk verschil voor de programmeur. Als je, om wat voor reden dan ook, parameters "eigenlijk" zou willen kunnen aanpassen in een eventhandler, dan hoef je daar dus geen variabelen voor te declareren als die parameters by value zijn gedeclareerd.

    Dat bepaald waarschijnlijk ook je eigen keuze of je parameters als const of als value declareert: "Heeft het überhaupt zin voor een toekomstige implementatie of overriden versie om deze parameters te kunnen aanpassen?"

    Het is ook een kwestie van (persoonlijke) discipline:
    Quote Originally Posted by F1
    > Delphi Help > Contents > Delphi Language Guide > Procedures and functions > Parameters > Parameter semantics > Constant parameters:

    Const also provides a safeguard against unintentionally passing a parameter by reference to another routine.
    Overigens, die const voor String-parameters zegt hetzelfde Help-topic ook iets over:
    Quote Originally Posted by F1
    Using const allows the compiler to optimize code for structured- and string-type parameters.
    Wat ook verklaart waarom die TPoint parameter in FindDragTarget const is.

    (*) 'k heb zojuist alle "overbodige" consts uit een unit van 4500 regels gehaald met als resultaat: 1792 minder tekens en 24 regels minder code.
    Last edited by NGLN; 20-Mar-09 at 21:53. Reason: (*)
    (Sender as TNLDUser).Signature := 'Groeten van Albert';

  15. #15
    Senior Member Henk Schreij's Avatar
    Join Date
    Sep 2002
    Location
    Heino (Raalte)
    Posts
    1,445
    Mensen, bedankt,
    En jij vooral Albert (NGLN).
    Deze laatste toevoeging is ook weer zeer waardevol.

    Morgen is mijn lezing voor beginners. In IJsselstein.
    Laat ze nu maar komen met hun moeilijk vragen

Page 1 of 2 1 2 LastLast

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •