2

I'm not sure if I understand correctly how pass by reference in Pascal works. Does it create an alias as in C++ (https://isocpp.org/wiki/faq/references) or does it work similarly as in C and the procedure gets a pointer to the variable and uses this pointer.

I guess I could formulate my question as: Does Pascal support true passing by reference, or is it done by call by sharing.

For example FreePascal reference states, that the procedure gets a pointer (https://www.freepascal.org/docs-html/current/ref/refsu65.html), but according to https://swinbrain.ict.swin.edu.au/wiki/Pass_by_Value_vs._Pass_by_Reference#Conclusion and for example https://cgi.csc.liv.ac.uk/~frans/OldLectures/2CS45/paramPassing/paramPassing.html#callByReference pass by reference in Pascal works differently than in C (where pointer is passed).

If anyone can explain a bit more about the differences or how the meaning of pass by reference has changed (in modern languages we say pass by reference, but in fact they are pass by value, like for example Java). What is then the original meaning of pass by reference and how does it work? And how is it then in Pascal?

Thank you very much.

pjSonic
  • 23
  • 1
  • 3
  • Not much difference in practice really, in pascal you can use the "var" keyword to pass the address. Where it says it's not supported you have to construct the pointer yourself, which you can also do in pascal. In all cases the procedure gets a pointer to the variable. – Sertac Akyuz Feb 09 '19 at 11:35
  • Pass by reference doesn't work differently than in C, but it has a different syntax. It is explained in various places, but try my article about pointers and references, [Addressing pointers](http://rvelthuis.de/articles/articles-pointers.html#refparams). – Rudy Velthuis Feb 09 '19 at 16:03
  • FWIW, Java **always passes by value**. But it passes *references* (pointers that don't look like pointers) to classes **by value** too. There, things like strings or arrays are classes too, so that works out. – Rudy Velthuis Feb 09 '19 at 16:09
  • 1
    Surely you mean references to objects, not classes. Which also literally contradicts the first part: Java's human-readable syntax passes primitives by value, and non-primitives by reference. Even if "inside the JVM, running the formal arguments in the compiled, and thus *different* code" it sees function calls that directly pass references by value. – Mike 'Pomax' Kamermans Feb 09 '19 at 17:08
  • 1
    @Mike: Assuming you were addressing me: I mean references to instances of classes, yes. In Java **nothing is passed by reference**. Reference types are **passed by value** too. References types are references to non-primitives . So non-primitives are not passed by reference; references to non-primitives are **passed by value**. Big difference. – Rudy Velthuis Feb 09 '19 at 17:22
  • 1
    @Mike: two of the many references supporting what I say: https://www.journaldev.com/3884/java-is-pass-by-value-and-not-pass-by-reference and https://stackoverflow.com/a/40523/95954. Again: **Java always passes by value**. This is apparently confusing for beginners. – Rudy Velthuis Feb 09 '19 at 17:26
  • @Mike: that Java can't pass by reference gets obvious if you try to write a swap routine for objects or for primitives. Won't work. There is a difference between passing **a** reference and passing **by** reference. Java can only do the former. – Rudy Velthuis Feb 09 '19 at 17:58
  • @RudyVelthuis not only java lacks pass-by-reference: C is another one! – linuxfan says Reinstate Monica Feb 09 '19 at 17:59
  • @Linuxfan: yes, sure. But Mike was contesting my statement about Java. C is a notable other one. But C, being originally a replacement for assembler, has pointers, so you can for instance easily write a swap routine in C. Not so in Java. – Rudy Velthuis Feb 09 '19 at 18:03

3 Answers3

4

Pass by reference

in Delphi, pass by reference (using var or out) means passing a pointer. But note that there is a difference between the semantics "pass by value" or "pass by reference" and the actual passing.

var or out

The difference with C is not the actual passing (by pointer), just what these keywords mean. Var simply passes by reference. Out treats certain managed types differently, because with out, you tell the compiler the input value is not guaranteed to be initialized. Otherwise, these are technically the same (but not semantically): the address of (IOW, a pointer to) the original values is passed.

Semantics <> actual passing

Semantics

  • The semantics of pass by value are that the routine gets a local copy of the original value, and that the routine can (if allowed) change it without affecting the original. The changes apply to the local copy and go away when the routine ends.
  • The semantics of pass by reference are that you are accessing (and perhaps modiyfing) the original.

Actual low level passing may be different

But the actually generated code may be different, for reasons of optimization. Especially larger structures (how large depends on version and platform -- this is documented somewhere and has changed over time) are often passed by reference (as pointers) even if the semantics say pass by value. In the prologue of the routine (the hidden code that runs before the first begin) such structures are then copied to the local frame of the routine. Note that this is not done in all calling conventions. Sometimes a full copy is made to the parameter stack before the call and no pointer is passed.

Since you still have a local copy, and don't modify the original, this is still considered pass by value, just like you declared. All the technical stuff happens transparently for the user, so the difference is only at a lower level. This only matters if you write assembler or must read generated code in the CPU window.

Const

If a value parameter is declared const, the original is not modified anyway, so the copying of a large structure to the local frame may be omitted and the values can accessed (read-only) by reference (pointer), even if the semantics are pass by value. Small values are always passed by value (in a register or on the stack), in such cases.

Although it doesn't make sense to have const var as parameter modifier (something is either constant or variable, but not both), you can still force the passing by reference of a const parameter, by using the [ref] modifier attribute: const [ref] X: Integer or [ref] const X: Integer. The integer would usually be passed by value (in a register or on the stack, depending on calling convention and platform).

Reference types

Note that if you pass reference types (e.g. objects, dynamic arrays, etc.) by value, the pass by value semantics only apply to the references themselves, i.e. you get a copy of them and you can modify the reference without affecting the original.

BUT: the items (objects, arrays, etc.) to which these references point can be modified. Only the references themselves are local copies, not to what they point. So if you call a method on an object reference passed by value, that object (on the heap) may be modified after all! That is not because pass-by-value or pass-as-const do not work properly, but because of what references are.

Conclusion

  • Pass by value means a copy of the original is made and that copy can be modified locally.
  • Pass by reference means a reference (pointer) to the original is passed and any modification modifies the original.
  • Under the hood, technically, in pass by value semantics, a pointer may be passed after all. If necessary, a copy of the original is made, so the original is not modified after all.
  • Passing reference types by value or even as const does not mean the original (heap) items to which they point are prevented from being modified. There is no C++-like const concept to prevent this.

A little more about references and pointers can be found in my (very popular) article Addressing pointers.

Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
  • 1
    Object pascal can pass objects or managed types. Without the `var` declaration, this means that even if the parameters are passed by value, the instance can be affected by the method. And the effect may be different if the type is a string or an object for example. – LU RD Feb 09 '19 at 16:53
  • @LURD: A reference is passed. If passed by value the **reference** is not modified, or can be modified without affexting the original reference. The item (object, interface) that is referred can still be modified. I'll add that to the answer. – Rudy Velthuis Feb 09 '19 at 16:56
  • @LU RD So, "Object Pascal" is close to the Java-ic semantics of passing objects and there an Object-parameter is equivalent to a Var-Object-parameter. Interesting! Guess with this we can enter a new level of fruitless "Java is pass-by-value"-discussion – Sam Ginrich Mar 22 '22 at 18:33
  • @SamGinrich, Rudy is sadly not longer with us. He will be missed. – LU RD Mar 23 '22 at 16:53
2

A simpler answer than the (very good) other.

does it work similarly as in C and the procedure gets a pointer to the variable and uses this pointer.

Yes, that's what happens under the hood. The procedure gets really a pointer, an address, to the variable. But the compiler, knowing that, makes it transparent. So, inside a procedure which declares a parameter "a", the statement:

a := a div 2;

can be compiled in two different ways. If the a parameter is declared normally, i.e. passed by value, the statement is compiled like:

1 - load the value at address "a"
2 - integer divide by two
3 - store the result at address "a"

If, instead, the parameter was declared as var, meaning passed by reference, the compiler does:

1 - load the value at address "a"
2 - load the value at address just loaded (it's a pointer dereferencing)
3 - divide
4 - store back

The above four statements are exactly what C compiles if the source is:

*a = *a / 2;

I guess I could formulate my question as: Does Pascal support true passing by reference ...?

The answer is absolutely yes, true passing by reference, and not many languages do this so well and cleanly. The source code for calling a procedure does not change, whether the procedure is called with "by reference" or "by value". Again the compiler, knowing how the formal parameters are to be passed, hides the details, unlike C. For example, take a call to a procedure which wants a parameter passed by value:

myproc(a);  // pascal and C are identical

Things get different if the procedure expect a pass by reference:

myproc(a);  // pascal: identical to before

myproc(&a); // C: the language does not hide anything

About this last point, someone thinks that C is best because it forces the programmer to know that the passed variable can be modified by the procedure (function). I think, instead, that pascal is more elegant, and that a programmer should know anyway what the procedure will do.

All this is for "simple" types. If we talk of strings (and modern pascal has two flavours of them), it's the same - in Pascal. The compiler copies, increments reference counts, does whatever is needed to have full support for passing by value or by reference. C language does not have something similar.

If we talk about classes, things are different, but they must differ anyway because of the semantics of classes.

I hope to have added something to the other complete answer.

0

The term "reference" was invented in the early years of programming languages, in Algol, Fortran or Pascal.

A reference is a sharing alias. The essential technical property of a reference is the address of the shared instance. In C++ a reference is equivalent to a de-referenced pointer.

// C++
int z = 29; // instance
int& alias = z; // reference
int* p = &alias; // pointer, address of z
int& r = *p; // reference

In Pascal references only exists as var-parameters of a procedures or functions or as de-referenced pointers

// PASCAL
z: INTEGER = 29; // instance
p: ^INTEGER = @z; // pointer, address of z
// p^ is a reference


PROCEDURE RefDemo(var x: integer)
VAR q: ^INTEGER;
BEGIN
   q =@x;
   RefDemo(q^);
END;

This var x: INTEGER exists equivalent in C++

void RefDemo(short int& x)
{
    short int* q = &x;
    RefDemo(*q);
}

In retrospective such reference p^exists in C, too, as *p. Though the inventors did not use this naming. They even decided to call a pointer a value, rather than the referenced instance (-value).

Now doing the same with objects

// Pascal
type 
   Books = OBJECT
      title: packed array [1..50] of char;
      author: packed array [1..50] of char;
      subject: packed array [1..100] of char;
      book_id: integer;
   end;
...

PROCEDURE RefDemo(var book: Books)
VAR q: ^Books;
    otherBook: Books;
BEGIN
   book.author[1] := '-';
   book := otherBook; // assigns all attributes
   RefDemo(q^);
END;

// C++
class Books
{
public:
   char title[50];
   char author[50];
   char subject[50];
   short int book_id;
}
...

void RefDemo(Books& book)
   Books *q;
   Books otherBook;
{
   q = &book;
   book.author[0] = '-';
   book = otherBook; // assigns all attributes [1]      
   RefDemo(*q);
}

// C emulation
typedef struct _Books
{
   char title[50];
   char author[50];
   char subject[50];
   short int book_id;
} Books;
...

void RefDemo(Books* book)
   Books *q;
   Books otherBook;
{
   q = book;
   book->author[0] = '-';
   *book = otherBook; // assigns all attributes [1]       
   RefDemo(*q);
}

Off Topic, but for completing comments:

In Java Object parameters behave precisely like the "By-Reference"-emulation in C, except we have no de-referentiation operator and no built-in assignment operator for complete objects instances as in [1].

Designers of Java followed ideas of C and breaking with there own paradigm of Java being object oriented language, they consider object references as values rather than object instances and this is the origin of endless discussions on calling-conventions.

We'll never get to know, what a Niklaus Wirth would say about an even grammatically weak statement like "Java is pass by value?".

Sam Ginrich
  • 661
  • 6
  • 7
  • *We'll never get to know, what a Niklaus Wirth would say about an even grammatically weak statement like "Java is pass by value?".* You can ask him. – LU RD Mar 22 '22 at 22:23
  • 1
    *`RefDemo(q^);`* in the second example (objects) will not compile, since pascal is a strict typed language. – LU RD Mar 22 '22 at 22:38
  • @LU RD ´VAR q: ^Books;´ corrected, else I would prefer to get a response to my subsumption of the type concepts, as I come from the school of Mr. Wirth and I am not really happy with certain settings of terms. – Sam Ginrich Mar 23 '22 at 11:23
  • 1
    If you have a separate question about type concepts of pascal vs java, I suggest you make a new question about that. Note that opinion based questions and questions that asks/invites for speculation are not welcome in stackoverflow. – LU RD Mar 23 '22 at 13:26
  • I have no question. May be meta stack is a field for identifying islands. – Sam Ginrich Mar 23 '22 at 14:09