# [프로그래밍 언어] 2. Names, Bindings, and Scopes

## 이름 Names & 5.3 변수 Variables

---

### 변수 Variables

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/133933_2YUI2K845DKODHyPep?q=80&s=1280x180&t=outside&f=webp)

- 컴퓨터 **메모리 셀**이나 **셀들의 모임**에 대한 **추상화**

- 프로그래머들은 흔히, 변수를 **메모리 위치들에 대한 이름**으로 생각

- 변수의 6가지 속성: **이름, 주소, 값, 타입, 수명, 영역**

### 이름 Names

- 변수의 기본적인 속성 중 하나

- **식별자 identifier**라는 용어와 혼용되어 사용

- 프로그램에서 어떤 개체를 식별하기 위해 사용되는 **문자열**
- → 문자 중간에 숫자는 괜찮지만 첫 번째로 오는 것은 안된다

**이름 형식**

- 언어에 따라 이름의 길이 제한이 존재 (Java, Python은 길이 제한 없음)

- C언어는 31글자까지 구분 가능 (32번째 글자부터는 달라도 같은 인수로 인식)

- 많은 언어들은 대소문자를 구분한다 (구분하지 않는 언어도 있음)

- **표기법**

    - **낙타 표기법 Camel Notation**

        - 이름이 길어지면 문장을 이름으로 만든다

        - 띄어쓰기를 하면 하나의 변수로 인식 X → 붙여써야 한다.

        - 첫 번쨰 단어를 제외하고 대문자로 시작 → `myStack`

    - **Snake Case**: C언어에서 `_`로 띄어쓰기 구분

    - **Kebab Notation**: `-`로 띄어쓰기 구분

### 주소 Address

- 변수와 관련된 기계 메모리 주소 → 연관이 그리 단순하지 않다

    - 변수의 이름이 없고 주소만 있어도 변수에 접근 가능
    -   → 힙 메모리, malloc을 리턴

    - 변수에는 값을 포함한다 → 초기화되지 않는 경우도 있다

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/133950_WEosognEV9lJLv7csD?q=80&s=1280x180&t=outside&f=webp)

- 많은 언어에서, 동일한 변수가 프로그램의 다른 시기에 다른 주소와 연관 가능

    - 부프로그램의 지역 변수 → 호출될 때마다 스택 메모리에서의 위치에 따라 주소 값이 달라질 수 있다

```javascript
x = [2, 3, 4]
y = x     # 참조가 복사
y[2] = 15 # [2, 3, 15]?
print(x)  # x = [2, 3, 15]
print(y)  # y = [2, 3, 15]
```

- Python에서 변수의 타입은 어떤 값을 넣는가에 따라 바뀐다

```javascript
i = 0; // 10을 i라는 변수 주소에
j = i; // i의 값을 j의 주소에
```

- **l-value**에는 주소, **r-value**에는 값이 들어간다

```javascript
int* a;
a = 100;
*a = 10;
```

**별칭 Alise** 

- 포인터와 같다

- 동일한 주소를 갖는 여러 개의 변수를 갖는 것이 가능

- **두 개 이상의 변수 이름이 동일한 메모리 위치를 접근**하는데 사용할 수 있을 때 **별칭**

- 변수의 값이 다른 변수에 대한 배정문에 의해 변경되는 것을 허용 → swapping 가능

- 별칭 생성 방법

    - C언어에서 공용체 타입 사용

    - C언어에서 두 개의 포인터 변수가 동일한 메모리 위치를 가리키면, 이들은 별칭

    - Java나 Python에서 참조 변수들도 별칭

- main 프로그램과 부프로그램(함수 등)이 존재

-   → 많은 언어에서 별칭은 부프로그램 매개변수를 통하여 생성 가능

### 타입 Type

```javascript
char c;
c = 7; // dtype에 따라 해석이 달라진다
```

- 타입이 결정 하는 것

    - 변수가 사용할 수 있는 범위

    - 그 타입의 값들에 대해서 정의되는 연산들의 집합

- 정수 타입은 덧셈, 뺄셈, 나눗셈, 모듈러 등의 산술 연산 포함 (실수 타입은 X)

### 값 Value

```javascript
typedef int INT;    // int: 데이터 타입
typedef struct A x; // struct A: 저장할 수 있는 값
```

- 변수에 연관된 **메모리 셀**이나 **셀들의 내용**

- 변수의 값을 때때로 r-value라고 부름

### 존속기간 Lifetime

- 언제 만들어서 언제 사라지는가

### 영역 Scope

- **Closure**: 함수 선어 시의 환경을 기억했다가 사용

- **Clojure**: 함수형 프로그래밍 언어

## 바인딩의 개념 The Concept of Binding

---

### 바인딩

- **속성**과 **엔터티** 사이의 **연관**

    - 엔터티 entity: 사람 또는 사물 (객체)

    - 속성 attribute: 엔터티는 속성을 가진다

    - 변수, 함수 등의 엔터티와 속성 사이에 **연관 binding**이 있다.

**C언어 기반 예**

```javascript
int i;  // 1) 컴파일 시점
i = 10; // 2) 실행 시간

// 1) float f
// 2) f = 5
float f = 5;
```

- 변수와 **타입** 사이의 연관 → **컴파일 시점**에 반인딩

- 변수와 **값** 사이의 연관 → **실행 시간**에 바인딩

- 변수와 **주소** 사이의 연관 → **메모리 적재 loading** 시점에 바인딩 (변수마다 다름)

- **연산과 심볼**과의 연관 → **언어 설계 (컴파일 설계)** 시점

- 라이브러리 **부프로그램** 호출과 부프로그램 코드와의 연관 → **링크** 시점에 바인딩

### 변수의 속성 바인딩

**정적 바인딩 static binding**

- 바인딩이 **실행 시간이 시작되지 전**에 일어나고

- 프로그램 실행 전체에 걸쳐서 **변하지 않은 상태**로 남아있다

**동적 바인딩 dynamic binding**

- 바인딩이 **실행 시간 중**에 일어나거나

- 프로그램 실행 과정에서 **변경**될 수 있다

### 타입 바인딩

- 변수는 프로그램에서 참조되기 전에 어떤 데이터 타입에 바인딩되어야 함

**정적 타입 바인딩**

- 변수에 바인딩된 타입은 프로그램 단위의 **존속기간 lifetime 동안 고정**

- **명시적 선언 explicit declaration**: 변수 이름들을 나열, 특정 타입이라는 것을 명세

    - C언어: `int i;`

- **묵시적 선언 implicit declaration**: 디폴트 규칙을 통해 타입 연관

    - Fortran: I, J, K, L, M, N으로 시작하면 Integer

- 정적 바인딩 언어: **C**, C++, **Java** 등

```javascript
int i = 10;
var j = 10;
```

- java에서 `var` 키워드는 우측 값으로 왼쪽 type을 유추한다

- 컴파일 시간에 int로 바인딩된다

- 한 번 바인딩되면 값이 바뀔 수 없기 때문에 정적이다

**동적 타입 바인딩**

- 변수의 타입이 선언문으로 명세되지 않으며, 이름의 철자로부터도 결정될 수 없음

- **배정문에서 변수에 어떤 값이 할당될 때**, 그 변후에 어떤 타입이 바인딩

- 배정문은 그 변수를 다른 주소, 메모리 셀에 바인딩 가능
- → 다른 타입 값은 프로그램 실행 동안 여러 번 변경될 수 있기 때문

- 동적 타입 바인딩되는 변수의 타입은 **일시적일 수 있음**

- 동적 타입 바인딩 언어: **파이썬**, JavaScript, Ruby, PHP 등

- **장점**

```javascript
spam = 'Hello' # 문자열 타입
spam = 40      # 정수 타입
spam = 1.0     # 실수 타입
```

    - 포괄적 프로그램 작성 등 프로그래밍에 유연성을 제공한다

    - **포괄적 프로그램**: 어떤 타입도 처리할 수 있은 함수

        - 두 개의 숫자를 파라미터로 받아서 더하는 함수를 만든다면

        - float, double, int 타입에 대해 add를 모두 만들어야 한다

        - 포괄적 프로그램을 사용하면 개발해야하는 메소드들의 수가 줄어든다

    - 데이터가 입력된 후에 그 변수에 할당될 때 올바른 타입으로 바인딩된다

- **단점**

    - 프로그램을 **덜 신뢰적**으로 만든다

        - 코드가 커지면 데이터 타입을 보장하지 못하기 때문에 신뢰도가 낮아진다

        - 따라서 타입 검사를 통해 검증해야한다

    - **비용**이 많이 든다

        - 실행 시간에 검사가 수행되어 실행 속도가 느려질 수 있다

        - 모든 변수가 현재의 타입을 유지하고 관리 → 메모리 비용 발생

### 기억공간 바인딩과 존속 기간

- 명령형 프로그래밍 언어 → 그 변수들에 대한 기억 공간 바인딩 설계로 결정됨

- 할당 allocation과 회수 deallocation

    - 할당: 변수에 바인딩되는 메모리 셀을 가용 메모리의 풀로부터 가져옴

    - 회수 : 변수로부터 바인딩이 해제된 메모리 셀을 다시 가용 메모리 풀에 반환

- 변수의 존속기간 lifetime

    - 변수가 특정 메모리 위치에 바인딩되어 있는 기간

    - 시작 시점: 변수가 특정 셀에 바인딩

    - 종료 시점: 그 변수의 바인딩이 그 셀로부터 해제

- 존속기간에 따른 변수들의 4가지 분류: 
- **정적 변수, 스택-동적 변수, 명시적 힙-동적 변수, 묵시적 힙-동적 변수**

**정적 변수 static variable**

- 프로그램 **실행 전** 메모리 셀에 바인딩

- 프로그램 **실행 종료까지** 동일한 메모리 셀에 바인딩

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/135541_gUoPMS1jgjGLBcHObB?q=80&s=1280x180&t=outside&f=webp)

- **전역 변수** → 프로그램 실행 전체에 걸쳐 사용

- **지역적 정적 변수** → 과거 민감 부프로그램에서 사용

    - class 안에 멤버 변수, 메서드에 `static`을 붙이면 class 변수, class 메서드

    - main 함수는 프로그램이 실행 되기 전에 존재해야한다

    - 프로그램이 실행되기 전 메모리에 존재해야하는 메서드에는 `static`을 붙임

- **장점**

    - **효율성**: 정적 변수에 대한 모든 주소지정은 직접적

    - 실행 시간에 **할당, 회수** 등 메모리 관리 비용이 필요 없기 때문에 **부담 없음**

- **단점**

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/135602_70LtK2epMvwb0fLfj7?q=80&s=1280x180&t=outside&f=webp)

    - 유연성 감소: **재귀적 부프로그램 지원 불가** (재귀는 변수들이 리셋 → 동적)

    - 기억공간이 **변수들 간에 공유될 수 없음**

**스택-동적 변수 static-dynamic variable**

- 변수의 선언문이 **실제 실행될 때**, 기억 공간에 바인딩

- 변수의 **타입은 정적**으로 바인딩

- 스택 -동적 변수는 **실행-시간 스택 run-time stack 에 할당**

- 장점: **유연성** 증가: **재귀**적 부프로그램 사용 가능

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/135639_pifoDu4Kk9HcTMcYWt?q=80&s=1280x180&t=outside&f=webp)

- 단점

    - 할당과 회수에 따른 **실행-시간 부담**

    - 간접 주소지정이 요구되어 **접근이 느려짐** → 스택에서 위치가 계속 바뀌기 때문

    - 부프로그램이 **과거 민감할 수 없음** → 필요시 `static` 사용

- 예시

    - C 함수, Java 메소드 **시작** 부분에 변수 선언

        - 함수나 메소드가 **호출**될 때 바인딩

        - 함수나 메소드 실행이 **종료**될 때 회수

    - C 함수, Java 메소드 **중간** 부분에 변수 선언

        - 함수 나 메소드가 **호출**될 때 바인딩

        - 변수 선언 부분이 실행될 때까지 **가시화되지 않음**

**명시적 힙-동적 변수**

- 프로그래머가 명세하는 명시적 실행-시간 명령어에 의해 할당되고 회수되는 **이름없는 (추상) 메모리 셀**

- 힙heap으로부터 할당되고 회수

- **포인터나 참조 변수**를 통해 참조될 수 있다

- 장점: 연결 리스트나 트리 같은 동적 구조체 구현 가능

- 단점

    - 포인터나 참조 변수의 올바른 사용 어려움

    - 요구된 기억 공간 관리 구현의 복잡성

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/135710_5RNBUtRMe9tvpSdVCD?q=80&s=1280x180&t=outside&f=webp)

```javascript
// Java
Integer intnode;
intnode = new Integer(1); // new: 명시적인 동적변수 할당, 1을 초기값으로 사용
// 회수 명령어 없음 -> dangling pointer 문제 해결
```

```javascript
// C언어
int *intnode;

// intnode: 전역 vs 지역에 따라 다름 
// (int *)malloc(sizeof(int)): 명시적인 동적 변수
intnode = (int *)malloc(sizeof(int));

free(intnode);
```

```javascript
// C++
int *intnode;
intnode = new int; // new: 명시적인 동적변수 할당
...
delete intnode; // delete: 명시적인 동적 변수 회수
```

**묵시적 힙-동적 변수**

- 값이 배정될 때 힙 기억 장소에 바인딩

- 장점: 최고의 유연성 →언제 어떤 타입으로도 변경 가능, 메모리 위치도 자동 변경

- 단점: 모든 동적 속성들을 유지하는데 필요한 실행-시간 부담

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/135741_X64KOcSYAfFfqU45vh?q=80&s=1280x180&t=outside&f=webp)

```javascript
# python
highs = [74, 84, 86, 90, 71]
highs = 17.3
```

```javascript
// JavaScript
highs = [74, 84, 86, 90, 71];
```

## 영역 Scope

---

### 변수의 영역

- 변수가 가시적인 문자들의 범위

- 변수가 어떤 문장에서 참조될 수 있으면, 변수는 그 문장에서 가시적

### 정적 영역

- 변수의 영역이 정적으로 **실행 전**에 결정

- 인간 프로그래머가 코드를 읽어 모든 변수의 타입 결정 가능

- 정적 영역과 관련하여 두 가지 유형이 존재

    - 부프로그램이 중첩될 수 있는 언어: Python, JavaScript 등

    - 부프로그램이 중첩될 수 없는 언어: C, Java등

**JavaScript 에서 함수**

```javascript
function big(){
    functions sub1(){
        var x = 7;
        sub2();
    }
    function sub2(){
        var y = x;
    }
    var x = 3;
    sub1();
}
```

- JavaScript는 동적 타입 언어, 정적 영역 언어

- javascript에서 `var`은 동적 타입 바인딩

- javascript는 부프로그램 간의 관계 이용

    - sub2()의 변수 x에 대한 참조 = big()에서 선언 X

    - x가 sub2()에 없는 경우 big()에서 탐색 **(부모 → 정적)**

    - sub1()에 선언된 x는 무시 (정적 부모가 아니기 때문)

**Java**

- Java는 정적 타입 언어, 정적 영역 언어

- Java의 `var`은 정적 타입 바인딩

- 중첩된 부프로그램의 허용 여부에서, 어떤 변수 선언은 **은폐될 수 있음**

- 어떤 언어에서는 은폐된 변수 참조 가능 → `this.x`

### 블록

- 많은 언어는 새로운 정적 영역이 실행 코드의 중간에 정의되는 것을 허용

- 지역 변수들은 **스택-동적 변수** 
- → 바인딩이 실행 코드 부분에 진입될 때 할당, 빠져나올 때 회수

- 코드의 부분을 **블록 block**이라 부름

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/135915_jSTzAlTvc8ED7uccmy?q=80&s=1280x180&t=outside&f=webp)

```javascript
if(list[i] < list[j]){
    int temp;
    temp = list[i];
    ...
}
```

```javascript
void sub(){
    int count;
    ...
    while(...){
        int count;
        count++;
        ...
    }
}
```

- sub()의 count는 while루프 내부의 코드로부터 은폐됨

- C와 C++에서는 이러한 코드 사용이 가능하지만, Java에서는 허용하지 않음 → 오류 방지

### 선언 순서

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/135933_tV3QchFYpEzj1m8VjI?q=80&s=1280x180&t=outside&f=webp)

```javascript
void func(){
    ...
    for(int count=0; count<10; count++){
        ...
    }
}
```

- 함수에 포함된 모든 데이터 선언이, 중첩된 블록에 속한 선언을 제외하고는 그 **함수의 시작 부분에 존재**해야함

- C, Java 등에서는 변수 선언의 문장이 위치할 수 있는 어느 곳에서나 허용

    - 복합문이나 부프로그램과 연관되지 않은 영역을 생성

    - 중간에 선언된 지역변수 → **선언문으로부터 그 선언문이 나타나는 블록의 끝까지**

### 전역 변수의 영역

- 파일에 속한 함수 외부에 위치한 변수 정의는 전역변수를 생성 → 모든 함수들에게 가시적

- C, C++의 경우

    - 전역변수의 선언과 정의를 가짐

    - 전역변수의 **정의**: 속성 명세, **기억공간의 할당 야기**

    - 전역 변수의 **선언:** 속성 명세, **기억공간의 할당을 야기하지 않음**

    - 함수 정의 외부에 위치한 변수 선언은 그 변수가 다른 파일에 정의됨을 명시 `extern`

**예시**

```javascript
day = "Monday"
def tester():
    print("The global day is ", day)
tester() # 정상적 출력: The global day is Monday
```

```javascript
day = "Monday"
def tester():
    print("The global day is: ", day)
    day = "Tuesday"
    print("The new value of day is: ", day)
tester() # UnboundLocalError오류 -> tester의 두 번째 day는 지역변수
```

```javascript
day = "Monday"
def tester():
    global day
    print("The global day is: ", day)
    day = "Tuesday"
    print("The new value of day is: ", day)
tester() # 정상적 출력
```

### 동적 영역

- 부프로그램들의 **상호 공간적 배치 관계**가 **아닌 부프로그램들의 호출 시퀀스에 기반**하여 **변수의 영역을 결정**

- 변수 영역이 동적인 언어들: APL, SNOBOL4, LISP 초기 버전

- 디폴트 영역 매커니즘이 정적, 변수가 동적 영역을 갖도록 선언을 허용: Perl, Common LISP

```javascript
function big(){
    function sub1(){
        var x = 7;
    }
    functions sub2(){
        var Y = x;
        var z = 3;
    }
    var x = 3;
}
```

- sub2()에 참조되는 식별자 x의 의미는 동적 
- → 컴파일 시간에 결정 못함

- 호출 시퀀스에 따라 x의 어느 한 선언에 속환 변수를 참조 가능

- big()이 sub1()을 호출하고 sub1()이 sub2()를 호출 
- → sub2()는 sub1()의 x를 참조

- big()이 sub2()를 직접 호출 
- → big()에 선언된 변수 x를 참조

## 영역과 존속 기간 Scope and Lifetime

---

**변수의 영역과 존속기간은 관련있는 것처럼 보임**

- Java 메소드의 지역변수가 존재하는 경우

    - 지역변수의 영역은 선언문에서 메소드의 끝,

    - 이 변수의 존기간은 실행이 메소드에 진입할 때 시작, 메소드 실행이 종료될 때 끝남

**외관상 관계는 다른 상황에서 성립되지 않음**

- C와 C++에서 static을 이용하여 함수에 선언된 변수

    - 함수의 영역으로 바인딩, 기억공간에서 정적으로 바인딩 → 정적, 지역적

    - **존속 기간**은 **프로그램 전체 실행 시간** → 과격 민감 프로그램 사용 가능

```javascript
void printheader(){
    ...
}
void compute(){
    int sum;
    ...
    printheader();
}
```

- C와 C++에서 함수가 다른 함수를 호출하는 경우

    - 변수 sum의 영역은 compute() 함수 내부에 완전히 포함

    - compute() 함수가 printheader() 함수를 호출하기는 하지만, sum 영역이 printheader()까지 확장되는 것은 아님

    - sum의 **존속기간은 printheader()가 실행되는 동안의 시간을 걸쳐 확장**

## 참조 환경 Referencing Environments

---

- **참조 환경**은 그 문장에서 가시적인 모든 이름의 집합

**정적-영역 언어에서 한 문장의 참조 환경**

- 그 지역 영역에서 선언된 변수들

- 그 조상 영역에 속한 가시적인 모든 변수들로 구성

```javascript
g = 3
def sub1():
    a = 5
    b = 7
    ...        # 프로그램 지점 1
    def sub2():
        global g
        c = 9
        ...      # 프로그램 지점 2
        def sub3():
            nonlocal c
            g = 11
            ...    # 프로그램 지점 3
```

- 프로그램 지점 1
- : 지역변수 a, b(sub1) 참조를 위한 전역변수 g, 배정에 g가 사용될 수 없음

- 프로그램 지점 2
- : 지역변수 c(sub2), 참조와 배정을 위한 전역변수 g

- 프로그램 지점3
- : 비지역 변수 c(sub2), 지역변수 g(sub3)

**동적-영역 언어에서 한 문장의 참조 환경**

- 그 지역 영역에 선언된 변수들과 현재 활성화되어 있는 모든 다른 부프로그램에서 선언된 변수들로 구성

- 활성화된 부프로그램에 속한 어떤 변수들은 참조 환경으로부터 은폐뙬 수 있음

```javascript
void sub1(){
    int a, b;
    ...      // 프로그램 지점 1
}
void sub2(){
    int b, c;
    ...      // 프로그램 지점 2
    sub1();
}
void main(){
    int c, d;
    ...     // 프로그램 지점 3
    sub2();
}
```

- 프로그램 지점 1
- : sub1()의 a, b, sub2()의 c, main()의 d

- 프로그램 지점 2
- : sub2()의 b와 c, main()의 d
- (main()의 c는 은폐됨)

- 프로그램 지점 3
- : main()의 c와 d

For the site tree, see the [root Markdown](https://slashpage.com/yerim-devnote.md).
