: 함수의 바디에 있는 코드를 복사해둔다.
: 함수의 기능인 파라미터 체크, 컴파일할 때의 기능등은 유지하면서 최적화하는 작업이다.
: 대부분 함수는 매개변수가 존재한다.
: 어떤식으로 진행하는지 방향 결정, 필요한 데이터를 전달할 때 사용
p(x);
구현 관점에서 두 가지로 전달할 수 있다.
1. x의 값을 copy 해서 전달하기. (= call by value, 값 복사이므로 별개 변수)
2. x의 주소를 전달한다. (= call by reference, 변수는 새로운 alias )
x : integer
procedure foo(y : integer)
y := 3
print x
...
x:= 2
foo(x);
print x
: 서브루틴 실행되기 직전에 call by value처럼 actual parameter를 복사하고, 서브루틴이 리턴할 때 값을 변경해서 리턴해준다.
In Pascal
In c
Fortran
: variable 자체가 reference인 언어에서는 도움이 되지 않아서 이용하는 방식(Smalltalk, Lisp, ML, or Ruby)
: alias 개념이 아닌, 같은 오브젝트를 공유한다는 개념이다.
: call by value, call by reference과는 다르다.
- 값을 전달하면 값을 지역 변수로만 사용 -> 전역에 있는 값은 변경 되지 않음 (Value)
- 객체의 인자를 던지면 그 객체가 가지고 있는 속성의 값을 변경은 가능 (Reference)
- 함수 내부로 할당 받은 객체에 새로운 메모리 값으로 할당은 불가능
참고
In Java
//pass by value
void f(A a){ //a는 b의 주소를 복사
a = new A(); //새로운 주소 할당
}
void main(){
A b = new A(); //b에 A를 가리키는 주소값
f(b);
}
//pass by sharing
class Temp2 {
Object o2 = new Integer(5);
void f(Object o) {
System.out.println("1: o2 = " + o2); //5
o = new String("temp");
System.out.println("o = " + o); //temp
System.out.println("2: o2 = " + o2); //5
}
void f2() {
f(o2);
}
void printO2(int n) {
System.out.printf("%d: o2 = %s\n", n, o2); //3, 5 (temp의 경우 f함수에서 o로 새로 할당되지 않는다.)
}
public static void main(String[] args) {
Temp2 t = new Temp2();
t.f2();
t.printO2(3);
}
}
In C#
f(&a)
void f(b* : type )
: c언어처럼 사용한다면 직접 엑세스 하려면 *b를 사용해야한다 (extra level of indirection) -> 자주 사용한다면 비효율적이다.Modula-3
C
읽기 전용일 때, callee 가 formal parameter를 수정하는 것을 허용하는가? 수정한다면 actual parameter에도 반영이 되는가?
Ada
: 3가지 passing 모델을 제공한다.
스칼라, 포인터인 경우, copying values로 구현되어있다.
constructed type인 경우, value, reference 두 가지 제공한다.
-> 두 가지 방식을 제공한다면 문제 발생
void swap(int& a, int& b) {
int t = a; a = b; b = t; }
int i;
int &j = i;
cout << a << b << c; // reference 리턴
*(*(cout.operator<<(a)).operator<<(b)).operator<<(c); //reference 리턴하지 않는다면
: 클로져는 함수에 대한 참조에 함께 전달되는 referencing environment를 함께 보따리처럼 가져가는 것을 의미한다.
In ada
1. type int_func is access function (n : integer) return integer;
2. type int_array is array (positive range <>) of integer;
3. procedure apply_to_A (f : int_func; A : in out int_array) is
4. begin
5. for i in A'range loop
6. A(i) := f(A(i)); //이때 k값도 같이 가져와야 함
7. end loop;
8. end apply_to_A;
...
9. k : integer := 3; -- in nested scope
...
10. function add_k (m : integer) return integer is
11. begin
12. return m + k; //k가 유지되어야 한다.
13. end add_k;
...
14. apply_to_A (add_k'access, B);
In C
void apply_to_A(int (*f)(int), int A[], int A_size) { //함수 참조
int i;
for (i = 0; i < A_size; i++) A[i] = f(A[i]);
}
Default (Optional) Parameters: 동적 스코프의 주요 용도는 서브루틴의 기본 동작을 변경하는 것이며, 이는 기본 파라미터로도 수행될 수도 있다.
int default_width = 16;
int default_base = 2;
void put(int item, int width = default_width, int base = default_base);
print("gkk", end="")
: end가 default valueNamed Parameters: 파라미터를 순서대로 지정하지않고, 이름으로 지정한다.
print("abc", 30, sep = ',', end = ' ') #python
Variable Numbers of Arguments: 개수가 정해져 있지 않는 파라미터
//java
static void print_lines(String foo, String ... lines) {
System.out.println("First argument is \"" + foo + "\".");
System.out.println("There are " + lines.length + " additional arguments:");
for (String str : lines) { // lines는 배열처럼 취급됨
Sysem.out.println(str);
}
}
//c#
static void print_lines(String foo, params String[] lines) {
Console.WriteLine("First argument is \"" + foo + "\".");
Console.WriteLine("There are " + lines.Length + " additional arguments:");
foreach (String line in lines) {
Console.WriteLine(line);
}
}
: 함수가 반환할 값을 나타내는 syntax는 매우 다양하다.
: 초창기 언어 (Algo60, Fortran, and Pascal)의 함수는 왼쪽이 함수의 이름인 할당 문을 실행하여 반환 값을 지정했다.
func A_max(A []int) (rtn int) {
rtn = A[0]
for i:=1;i<len(A);i++ {
if A[i]>rtn{rtn=A[i]}
}
return
}
: 초창기 언어에서 함수에서 반환할 수 있는 변수의 타입을 제한하기도 했다.
def foo():
return 2, 3
...
i,j=foo()