CSC447

Concepts of Programming Languages

Argument Passing

Instructor: James Riely

Argument Passing

  • Consider
    
    def f (x:String, y:Int) = x * y
    
    f ("hello", 10)
                  
    • x, y - formal parameters (or parameters)
    • "hello", 10 - actual parameters (or arguments)

Argument Passing

  • Subtleties in passing arguments
  • What does a call to f print?
    
    void g (int y) {
      y = y + 1;
    }
    
    void f () {
      int x = 1;
      g (x);
      print (x);
    }
                  

Call-By-Value (CBV)

  • Most PLs use call-by-value (CBV) by default
  • To run g (e)
    • evaluate e to a value v
    • pass a copy of v to g
    • callee changes to copy of v not visible to caller

Call-By-Value Example

  • For g(x+1) with x = 5
  • x+1 evaluates to 6
  • a location containing 6 is given to g
  • location could be memory or a register

Call-By-Value Example

  • For g(x) with x = 5
  • x evaluates to 5
  • a location containing 5 is given to g
  • location is different to that of x!

Call-By-Value Answer

  • Prints 1 in a CBV PL
    • I.e., x=1 after call to g

void g (int y) {
  y = y + 1;
}

void f () {
  int x = 1;
  g (x);
  print (x);
}
          

Call-By-Reference (CBR)

  • Some PLs use call-by-reference (CBR)
  • To run g (e)
    • evaluate e to an l-value r
    • pass the l-value r to g
    • callee changes via r are visible to caller

Call-By-Reference Example

  • For g(x) with x = 5
  • x evaluates to the location of x
  • that location (of x) is given to g
  • g has an alias of x
  • writing to the alias is visible to caller

Call-By-Reference Answer

  • Prints 2 in a CBR PL

void g (int y) {
  y = y + 1;
}

void f () {
  int x = 1;
  g (x);
  print (x);
}
          

CBR and Temporaries

  • Can temporary values be passed as l-values?
  • g(x+1) is not obviously legitimate in CBR
  • Some languages reject it
  • Perl allows it
  • Modern C++ has a more complex story

CBR In Perl

  • Perl uses CBR

sub g { 
    $_[0] = $_[0] + 1;
}

sub f {
    my $x = 1;
    g ($x);
    print ("x = $x\n");
}

f ();
          

$ perl ./cbr.pl 
x = 2
          

CBR In Perl

  • But allows temporaries!

sub g { 
    $_[0] = $_[0] + 1;
}

sub f {
    my $x = 1;
    g ($x + 1);
    print ("x = $x\n");
}

f ();
          

$ perl ./cbr.pl 
x = 1
          

Simulating CBV In Perl

  • Simulate CBV by creating copies explicitly

sub g { 
    my ($y) = @_;
    $y = $y + 1;
}

sub f {
    my $x = 1;
    g ($x);
    print ("x = $x\n");
}

f ();
          

$ perl ./cbr.pl 
x = 1
          

Simulate CBR In C

  • Explicitly pass, receive, access a pointer

void g (int *p) {
  *p = *p + 1;
}

int main () {
  int x = 1;
  int *q = &x;
  g (q);
  printf ("x = %d\n", x);
  return 0;
}
          

$ gcc -o pointer pointer.c 
$ ./pointer 
x = 2
          

CBR in C++

  • C++ has reference types int&
  • Unlike int*, creates references (aliases) implicitly

#include <iostream>

using namespace std;

void g (int& y) {
  y = y + 1;
}

int main () {
  int x = 1;
  g (x);
  cout << "x = " << x << endl;
  return 0;
}

          

$ g++ -o reference reference.cpp 
$ ./reference
x = 2
          

CBR in C#

  • C# has reference parameters ref int
  • Unlike int& must also be used by caller

using System;
class Test {
  static void g (ref int y) {
    y = y + 1;
  }

  static void Main () {
    int x = 1;
    g (ref x);
    Console.WriteLine("{0}", x);
  }
}
          

$ mcs cbr9.cs
$ mono cbr9.exe
2
          

CBR in C++: passing a non-lval


#include <iostream>

using namespace std;

void g (int& y) {
  y = y + 1;
}

int main () {
  int x = 1;
  g (x + 1);
  cout << "x = " << x << endl;
  return 0;
}

          

$ g++ -o reference reference.cpp 
reference.cpp: In function ‘int main()’:
referencs.cpp:11:8: error: invalid initialization of non-const
  reference of type ‘int&’ from an rvalue of type ‘int’
   g (x + 1);
        ^
references.cpp:5:6: error: in passing argument 1 of ‘void g(int&)’
 void g (int& y) {
      ^
          

Simulate CBR In Java

  • Java has only a restricted form of pointers, called references
    • must point to heap-allocated objects
    • cannot point to stack-allocated data
    • cannot point to primitive types
  • Java references cannot be forged
    • not from integers via casting
    • not from other references via pointer arithmetic
  • Objects only accessed via references
    • unlike C++
    • Java has no address-of & operator

Reference types and value types

Simulate CBR In Java

  • Heap-allocated object with field of intended argument type
  • Pass a reference to the object instance by value

class IntRef { int n; }

public class Ref {
  static void g (IntRef r) { r.n = r.n + 1; }

  public static void main (String[] args) {
    IntRef s = new IntRef (); s.n = 1;
    g (s);
    System.out.println (s.n);
  }
}
          

$ javac Ref.java 
$ java Ref
2
          
  • Can also use an array

Sharing Vs CopyIn/CopyOut

  • Two possible implementations of CBR:
    • Make the parameter a pointer
    • Copy in, then copy out.
  • Are these the same?

Sharing Vs CopyIn/CopyOut


using System;
class SharingVersusCopyInCopyOut {
  static void callByReference (ref int x, ref int y) {
    x = x + 1;
    y = y + 1;
  }
  static void Main() {
    int a = 1;
    callByReference (ref a, ref a);
    Console.WriteLine("a = {0}", a);
  }
}
          

$ mcs cbr8.cs
$ mono cbr8.exe
3
          

Scala: CBV

  • Scala is call by value

def f (x: Double) : Double = 
  val x1 = x
  val x2 = x
  x1 - x2
println ("f= " + f (Math.random()))
          

Scala: Passing a function

  • Scala allows functions as parameters
  • A function that takes no arguments can be seen as a delayed value, also called a thunk

def g (x: () => Double) : Double = 
  val x1 = x()
  val x2 = x()
  x1 - x2

println ("g= " + g (() => Math.random()))
          

Scala: Call by Name

  • Scala has a special syntax for using thunks as parameters
  • Call-by-name parameters are non-strict

def h (x: =>Double) : Double = 
  val x1 = x
  val x2 = x
  x1 - x2

println ("h= " + h (Math.random()))
          

Scala: Uses of Call by Name

  • Call-by-Name can be used to create new control constructs
  • For example, we can define while loops:

def myWhile (cond : => Boolean) (body : => Unit) : Unit = 
  if cond then
    body
    myWhile (cond) (body)
          

var i = 3
myWhile (i > 0):
  println ("i= " + i)
  i = i - 1   
          

Brackets are required here

Macro Expansion

  • C macro expansion has a similar effect

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int f (int i) { return i - i; }
#define h(i) (i)-(i)
int main () {
  srand(time(NULL));
  printf ("f=%d\n", f(rand()));
  printf ("h=%d\n", h(rand()));
}
          

$ gcc -o cbn4 cbn4.c
$ ./cbn4
f=0
h=-955465947