Parameter Passing

Pages: 12
Well, if there's one thing internet fora are known for, it's the promotion of consensus :)
closed account (z05DSL3A)
I would still maintain that there is no such thing as Pass-by-pointer.

To me pass-by-value and pass-by-reference have a specific meaning. Pass-by-value means that a copy is made and assigned to the parameter. Pass-by-reference means that a reference is created for the parameter.

When the parameter has a pointer type, a copy of a pointer is assigned to it on calling. This copy of the pointer can be messed around with and it will not effect the pointer used to call the function.

http://en.wikipedia.org/wiki/Evaluation_strategy
Yes, but you are messing with semantics.

When talking about calling conventions, we are interested in the source object relative to the local argument value's type. For example:

1
2
3
void foo( int );
void foo( int* );
void foo( int& );

In all cases, we are interested in passing an int value to the function. It is the means by which that integer value is passed that is of interest. Pass by value (a copy of the integer value is made), pass by indirect reference or pass by pointer (a copy of the address of the integer is made and subsequently used to access the integer value), and pass by direct reference or pass by alias (where the argument is treated as if it were the original integer value).

The difference becomes clear in the body of the functions:

1
2
3
int n = 12;
foo( n );
cout << n << endl;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void foo( int x )
  {
  x = 42;  // Our local copy of n is modified. n is not.
  }

void foo( int* x )
  {
  *x = 42;  // Here we dereference our local copy of n's address to modify n.
  }

void foo( int& x )
  {
  x = 42;  // Here we modify n via its local alias.
  }
The only difference between the reference and the pointer is that the pointer shows that the value is not local, and is therefore in my opinion more readable. Therefore I translate your calling conventions as:
1. pass by value.
2. pass by visible pointer that can be null, indicating a destroyed or unsupplied object.
3. pass by invisible pointer that cannot be null, but may still be invalid i.e. reference a destroyed object.
References are basically an underpowered, less readable version of pointers.
Last edited on
closed account (z05DSL3A)
but you are messing with semantics.

I am not messing with semantics and I am happy to be proven wrong in my understanding but so far no-one has.

I spent some time re-reading some areas of Stroustrup[1] last night. He makes takes about by value and by reference and no mention of by pointer.

Stroustrup wrote:
The semantics of argument passing are identical to the semantics of initialization. In particular, the type of the actual argument is checked against the type of the corresponding formal argument, and all standard and user-defined type conversions are performed.



Duoas wrote:
When talking about calling conventions, we are interested in the source object relative to the local argument value's type.

Okay, here is my take on
1
2
3
4
5
6
7
void foo( int X, int * Y, int & Z);

int a = 0;
int *b = &a;
int & c = a; 

foo(a, b, c);


The types of the formal arguments (parameters) of foo() are; int, pointer to an int, and reference to an int, respectively.

When you call foo() with the actual arguments a, b, and c; how do they get assigned to the corresponding formal arguments (local variables of foo())? I think we all agree that a is passed-by-value and c is passed-by-reference. Now b, how does a pointer to an int get assigned to a pointer to an int? Surly it is copied by value like any other non-reference type i.e. passed-by-value. Yes the value is an address. Yes, you can use indirection on Y to get to the value of a but that has nothing to do with how Y was initialised by b.

To me pass-by–pointer makes no sense; it would suggest that there is a point involved in the initialisation of Y by b.

Hopefully this makes sense and you can see my reasoning for say there is no such thing as pass-by-pointer. It is all to do with how the formal argument is initialized and nothing to do with how it is later used.

Again, Sorry for dragging this out.

Edit:
To answer the original question, "List three ways of passing a parameter (or return value) in C++.", I would say that you can pass/return a value, a reference, or a pointer.

Edit 2:
I guess this is a pet peeve of mine, I hate it when terms that have a specific meaning are misused, corrupted or otherwise perverted, rendering them meaning less or tainting them with negative connotations.


--------------
[1] The C++ Programming Language Third Edition, Bjarne Stroustrup
Last edited on
Duoas wrote:
In all cases, we are interested in passing an int value to the function.


Just not true. Maybe you never have the need to have functions work on pointers (rather than the object obtained by dereferencing a pointer), but I do and so do lots of other people.

Duoas wrote:
a copy of the address of the integer is made


A copy of a pointer is made. A pointer is not the same thing as an address. A pointer is a complete object that can hold an address value; an address is just a concept, a number.
Last edited on
I am not messing with semantics

Yes, you are.

The OP isn't interested in being a compiler. The OP is interested in getting some type of OBJECT into his function. When you start talking about an intermediate object (a pointer) as if it were the OBJECT (the integer, or whatever is being addressed), then things are changed.

We are looking at the same thing in two different ways, and that is why we are at odds here. Stroustrup is interested in thinking like a compiler. People who write compilers think like compilers. But a compiler is the implementation of a language specification, which is not a compiler (though many language documents, C and C++ documents in particular, treat it that way).

I would say that you can pass/return a value, a reference, or a pointer.

Er, isn't that the same as saying "pass by value", "pass by reference", and "pass by pointer"? This is the semantic I am talking about.

You say, "No it is not the same" because you are interested in the mechanics of how the passing happens.

I say that the way the target OBJECT is accessed is what is at issue here.
  - by value - a copy of OBJECT is given to access
  - by pointer - a pointer referencing the OBJECT is given
  - by reference - an alias to the OBJECT is given

If you stick with the "a pointer is a value" way of wording things, then all the existing C literature wherein we pass by reference must be invalidated... since C doesn't actually have a "reference" type, and all arguments are actually passed by value on the call frame. A pointer is a reference, just as it was in C. It is an indirect reference, just as it was in C, but it is a reference none-the-less.

How do we distinguish between an indirect reference via pointer and a direct reference via alias when talking about it? Terminology, of course.

An indirect reference involves an intermediate object - a "pointer".
A direct reference does not (or at least it hides it if it does) - a "reference".

This is the semantics, or meaning, given when we ask how an object is passed to a function. We don't care about the meaning of how the intermediate objects, if any, are passed.

Duoas wrote:
a copy of the address of the integer is made



A copy of a pointer is made. A pointer is not the same thing as an address. A pointer is a complete object that can hold an address value; an address is just a concept, a number.

NO. A copy of the address is made.

A pointer is a type.
An address is a value.

Types: int, bool, double, std::string, ...
Values: 47, true, -3.219, "Hello world", ...

You don't pass types, you pass values.

Duoas wrote:
In all cases, we are interested in passing an int value to the function.


Just not true. Maybe you never have the need to have functions work on pointers (rather than the object obtained by dereferencing a pointer), but I do and so do lots of other people.

You are committing a red herring and attempting others...

If the OBJECT being given as argument to the function is a pointer type, then there are three ways to pass that pointer:

1
2
3
void foo( int* ) -- by value
void foo( int** ) -- by pointer
void foo( int*& ) -- by reference
And, of course, inside the function you will dink with it the same ways:
1
2
3
int x = 42;
int* n = &x;
foo( n, &n, n );
1
2
3
4
5
6
7
int y = -7;
void foo( int* pv, int** pp, int*& pr )
  {
   pv = &y;  // n is not modified
  *pp = &y;  // n now addresses y (instead of x)
   pr = &y;  // n now addresses y (instead of x)
  }

This is more easily observed if you use a friendly typedef:

 
typedef int* pint;
1
2
3
void foo( pint ) -- by value
void foo( pint* ) -- by pointer
void foo( pint& ) -- by reference
1
2
3
int x = 42;
pint n = &x;
foo( n, &n, n );
1
2
3
4
5
6
7
int y = -7;
void foo( pint pv, pint* pp, pint& pr )
  {
   pv = &y;  // n is not modified
  *pp = &y;  // n now addresses y (instead of x)
   pr = &y;  // n now addresses y (instead of x)
  }


@Grey Wolf
I also have a pet peeve when terms that have specific meanings are applied in the wrong context.

I believe you have chosen a context convenient to writing compilers.

I also believe that the OP is not interested in writing a compiler, but in understanding the functioning of the language implemented by compilers.

Our contexts differ. And all meaning has value only in context.

Also, I have not made any term used here meaningless or given it any kind of negative connotation. Please watch your barbs, as I have not treated you unkindly. I only said that I think you are mixing contextual meanings, ie semantics -- and I made no judgement on whether or not that was intentional. (But I'll say here that I don't think it was. I just think that you are looking at this from a different angle, ie context, and I think that your angle is not the OP's interest.)
closed account (z05DSL3A)
A pointer is a type.
An address is a value.

Types: int, bool, double, std::string, ...
Values: 47, true, -3.219, "Hello world", ...

You don't pass types, you pass values.

So a pointer is passed by value?
----
edit:
I know that was a bit flippant but it did kind hit the nail on the head for me.
----
Duoas,
I'm sorry if you took a general comment as a barb. It was not mean specifically about anything said in the thread but life in general. At the time I wrote the edit I was just thinking about why this is such an issue to me. Fro example, I used to not mind being called or referring to myself as a hacker, now due to misunderstanding and misuse this term has negative connotation.
Last edited on
LOL. Yes, everything is technically passed by value. :-)


It is because of all those stupid movies about anti-hero crackers calling themselves "hackers".
Crackers and script kiddies are scum, but they want to think of themselves as good guys, so they call themselves hackers.

Such is the way with language. The ignoble steal the names of the noble, and common words make an uncommon vocabulary. Religionists have been doing it successfully for years, disagreeing with each other vehemently while using the exact same words and phrasing. Polititions too, come to think of it.



Wait...


OH NO! It really is all just a mind game! AAAAAAAAAaaaaaaaaaaaaaaaaaaaaaaaaaaahhhhhhhhhhhhhh...........
NO. A copy of the address is made.


I disagree; I genuinely believe that if I pass in a pointer, a copy of that pointer is made. I shall look into it and see if I am in fact completely wrong on that, and no copy of the pointer is made.

I expect the crux of this is that I simply do not accept the validity of the idea of pass-by-pointer as a stand-alone concept. For me, that is identical to pass-by-value.
Last edited on
closed account (z05DSL3A)
I wrote:
I would say that you can pass/return a value, a reference, or a pointer.
Duoas wrote:
Er, isn't that the same as saying "pass by value", "pass by reference", and "pass by pointer"? This is the semantic I am talking about.

In all seriousness I do think they are semantically different. My version is what is passed the other is how something is passed.
closed account (z05DSL3A)
I disagree; I genuinely believe that if I pass in a pointer, a copy of that pointer is made. I shall look into it and see if I am in fact completely wrong on that, and no copy of the pointer is made.

I expect the crux of this is that I simply do not accept the validity of the idea of pass-by-pointer as a stand-alone concept. For me, that is identical to pass-by-value.

This is the meaning of pass-by-value. The value of the actual argument is taken, passed via the stack, and used to initialise the formal argument (local variable) of the function.
Last edited on
I disagree; I genuinely believe that if I pass in a pointer, a copy of that pointer is made.
Then you've missed the whole conversation.

When talking low-level implementation, you are correct. There is only pass-by-value.

When talking high-level language construct, you are not correct. There are three ways in C++ to access an object: get a copy of it, get a pointer to it, or get an alias to it. That is, by value, by indirect reference, or by direct reference. I can't say this any more clearly, so if you continue to miss the point you need to reconsider things for a while.


You are also mixing your vocabulary when it comes to pointers.

A type is an intangible thing, a blueprint describing the form of an object.
An object is a tangible thing, that exists -- the instanciation of a type.

A pointer is a type, not an object.
An address is an object, not a type.
An address is the instantiation of a pointer. Or, in other words, a pointer "holds" an address.

You say the same thing of integers. An integer is a type. 5 is an object. An integer "holds" the value 5. That is, 5 is the instantiation of an integer.

When you pass an integer into a function, you get a copy of the '5' in the integer, expressed as an integer type. You might say that you got a copy of the integer, just as I may say I got a copy of a letter sent to everyone on my block, but the type of thing (a letter) is not what is copied, it is the content, what is written in the letter, that is copied. The physical letter itself is actually distinct from all my neighbors' letters.


You are also confusing yourself because, techically, 5 itself is an abstract concept. There is no such thing as a '5'. You may have five apples -- real objects; you may have a drawing of a '5' -- a real object; but you cannot have a '5' -- it is not a real object. It is an abstraction used to reason about real objects.

However, computers don't deal with real objects. They deal with abstractions. Hence, when we talk about a '5' or an 'address' in terms of a computer, we are talking about the instantiation of an abstract idea. Meaning, there is some collection of real magnetic forces comprising a series of bits that represent the number '5' or the address of some other piece of memory in the computer.

What is amazing and wonderful is that handling these abstractions has such a profound effect on real things - printers produce reports and letters, robots make cars, etc.


@Grey Wolf
Semantics includes context. Our contexts are different. I think the OP is about how something is passed, not what is passed.
closed account (z05DSL3A)
Here is a question then: In the function, foo(int A, int * B, int & C);, what is passed and how is it passed?
Last edited on
...low-level implementation, you are correct. There is only pass-by-value. When talking high-level language construct


To me, there is only the low-level implementation, and high-level language constructs are approximations (probably due to how I started - I began in embedded software, where assembler and C were the order of the day, so that informs my thinking); this probably doesn't help, given that we come at this from opposite directions. I suspect this is why I don't accept pass-by-pointer; at the low level, it looks identical to pass-by-value.

A pointer is a type, not an object.


If we both agree that upon creation (that is, instantiation) of a pointer object, a section of memory that was not in use before is now in use, and it holds a readable, physical representation of something that is commonly interpreted as an address, then we mean the exact same thing and are arguing over wording.

There are three ways in C++ to access an object: get a copy of it, get a pointer to it, or get an alias to it.


I agree completely with that (in the context of how you get that object into a function, that is; the unspoken fourth way is to just access directly by name in scope of its existence, but that's trivial for the purposes of this discussion). It's the act of passing each of those into a function where we quibble; I see only two methods there - pass by value and pass by reference. I make no distinction for pass by pointer, as above. I seems that we have now agreed completely with each other and found the bounds of our differences, and it is completely in wording.

Last edited on
@Moschops

Yes, that is exactly it!

Wording is everything! But words only mean something in context.

If I were to go to work and say to one of the children, "yo, 'sup?" they'd respond likewise.

If I were take my white face to Camden and waltz up to the nearest dealer on the corner and say, "yo, 'sup?" I'd get shot.

From the point of view of the machine, and how things work underneath, then the answers are limited, and you are exactly right.

From the point of view of the language, and students of that language, then there are other ways to consider it.

Programming and thinking are both modulated by levels of abstraction. High-level languages exist so that I don't have to care how the machine actually works underneath. The interest is in how the language works to convey a concept, like a reference.


@Grey Wolf

You are using equivocation against me.

There are at least two answers, no?

A is a copy of an integer, passed by value (type: integer)

B is a copy of a pointer to an integer, passed by value, which references (indirectly) an integer (type: pointer to integer [intermediary object] and type: integer [referenced object])

C is a direct reference to an integer, which, depending on what your compiler chooses, may actually be translated into a call frame reference (due to inlining) or it may be a pass-by-value pointer to the integer which is automatically dereferenced for the user (type: integer and type: pointer to integer --> automatic dereference --> type: integer).

Do you care more about the mechanics or do you care about the integer value that the caller is trying to give the function?
Programming and thinking are both modulated by levels of abstraction.


Possibly informed by the kind of programming I tend to do, one of the things I like most about coding is that I don't have to abstract; I can forego analogies (some of which are truly atrocious - I recall being told once that a class is like a cookie-cutter, which only made sense if you already knew what a class actually was, and was just confusing otherwise) and view things in terms of physical representation. It is my personal belief that teaching as low-level as possible is the way to go for students, if only so that they will understand the limits of the abstractions when they move up to them, but that's obviously not shared by everyone. I do tend to find that teaching pointers works best if one starts at the very low level of objects in memory, but that might just be because pointers are generally badly taught. I expect you've seen me trying to explain them as objects in memory around here somewhere.

To be fair, when coding I don't physical representation, but think in terms of numbers represented by physical states, rather than the physical state itself.
closed account (z05DSL3A)
I just wanted to see how you answered to see where you are coming from.

Do you care more about the mechanics or do you care about the integer value that the caller is trying to give the function?
I care more about clarity of meaning. If you say pass-by-value, I think of the mechanics of how the actual argument is passed to the formal argument. I believe that this meaning is fairly well defined. If the phrase is used for a more abstract level and similar phrasing is added, then the precise meaning is lessened and confusion creeps in. It is this that I have a problem with. Imagine if people start calling a pointer a reference, after all it does refer to an object.

When I'm designing I care about the integer value and where it needs to be. When I am writing code it is all about the mechanics.
Moschops wrote:
one of the things I like most about coding is that I don't have to abstract; I can forego analogies

But programming is about building abstraction upon abstraction, and abstractions have nothing to do with analogies. When I say "square root of x" you know precisely what I mean. There's no analogy involved. Abstraction is about naming things so you can think about them as a logical unit.

Thus, while low-level knowledge is certainly important, the ability to abstract is absolutely essential for programming. There's this lecture from SICP (they're available online and very recommended) in which Abelson or Sussman says something along these lines: "knowing what not to look at is just as important as knowing what to look at". It's no coincidence that the most expressive languages are the ones farther away from the machine model. The machine has to be very simple. We, as programmers, would like to express very complex thoughts. High level programming languages allow us to abstract a lot of that complexity away so that we can intellectually grasp problems that would otherwise be too complicated for humans.
Last edited on
Here's an illustration of how I visualize the two categories.

A staffing manager receives a stack of applications of job candidates. This is pass-by-reference for the candidates, and pass-by-value for the application documents. The documents may have been copied, transferred, etc, but that is irrelevant. The candidates are "referred to" through the contents of the documents. Pass-by-reference stacks on top of pass-by-value. This is not the academic interpretation, I know.

Computers can pass by reference, because they can create a "name" for an object, and then identify the entity that corresponds to that name by browsing a collection. The "name" can be a pointer or c++ reference and is essentially (technology-wise) a value, no matter what is the syntax. Even passing an index can be used to "refer" to an object, as long as the index is for some well-known storage where you can use it to access the corresponding element. This is my unofficial interpretation. It is aimed at algorithmic design. I don't care to de-conceptualize the terminology in benefit of the target language or implementation technique.

I see pass-by-reference as a method to:
1. commit changes to object that the caller can reclaim/observe
2. observe changes in object that the client can modify (while you still execute)

All other stuff, like efficient passing of big structures is implementation specific. The C++ language has official terminology of-course, albeit IMHO a tad bit confusing. From language design point of view, the difference between references and const pointers is mostly syntactical. I think that the whole by-pointer/by-reference/by-value distinction is in practice propelled more by convention than anything.

Regards

EDIT: In summary, I am trying to say that for me, pass-by-value and pass-by-reference are not exclusive phenomena. They stack. Also, you can not be certain that an object is actually provided by-reference from the prototype. At least for me, this is property of the algorithm.
Last edited on
Topic archived. No new replies allowed.
Pages: 12