03. Names, Scopes and Bindings - (1)

Jimin Lim·2021년 10월 28일
0

Programming Language

목록 보기
2/9
post-thumbnail

3.0 Abstraction

High-Level Language

  • Fortran, Algol(이후 영향 미침), Lisp과 같은 초창기 언어 → high level
    • syntax(문법), semantic(의미)이 추상화됨: (어셈블리 언어에 비해)
    • 컴퓨터로 해결하기 위해서 모두 고려하기 힘듦 → 추상화함
    • 기계에 의존적이지 않음
    • 사람이 프로그래밍할 때, 이해할 때에 더 쉬움

Names

  • 뭔가를 나타내는 문자열
    • a=3 : 3이 있는 공간의 이름
    • l-value: 공간, r-value: 값
  • 식별자로 사용 (alphabet + number)
  • 변수, 상수, 연산자 등을 참조
  • 복잡한 코드와 연결 (변수, 함수, 클래스)

Abstraction

  • 특정 컴퓨터 구조의 자세한 내용으로부터 언어의 기능 분리시킴
  • Subroutine, function - Control abstractions
    • 복잡한 코드 부분은 숨기고 간단한 interface만 보이도록 함
    • 실제로 호출하는 부분을 숨김
  • Class - Data abstractions
    • 클래스의 정보, 함수를 감춤
    • 내부 구조에 대해서는 자세히 알 필요 없음

3.1 The Notion of Binding Time

Binding

  • 이름과 이름을 나타내는 무언가를 연결
  • 함수와 함수 코드, 변수와 메모리 공간
  • Binding Time
    • 바인딩이 언제 일어나는가
    • 코드 작성, 컴파일, 링크, 로드, 메모리 올릴 때
    • early binding time: 효율성 증대시킴
    • later binding time: 유연성 증대시킴

Binding Time

  • Program writing time
    • 프로그래머가 선택할 때
  • Compile time
    • if문을 작성했다(고급언어) → 기계어로 바꿈
  • Link time
    • 기존 함수(standard subroutines), 내가 만든 함수 합치는 과정
    • ex) 기존 함수: print-system이 제공하는 함수 (언어마다 다른 모듈)
      • 메인을 작성하다가 printf 사용 → 컴파일되어 있는 곳으로 가야함
    • int a; → a라는 변수의 공간을 어딘가에 잡아둬야함, 내부에 존재 → link
    • 따로 컴파일 된 것을 링크
  • Load Time
    • 운영체제에서 메모리에 코드, 데이터를 올려서 실제 실행할 수 있는 상태를 만들어 주는 과정
    • Link time에 만들었던 address, load address 다름
      • 가상주소 → link time, 물리주소 → run time
      • 실제 메모리에 올렸을 때 그 때의 주소는 다름
      • virtual(link) vs physical(run time에 바뀔 수도)
  • Run Time
    • 프로그램 처음부터 끝까지
    • 바인딩 이루어 짐
    • elaboration time: declaration이 처음 보여질 때
      • storage allocation and binding process
    • 함수 시작 시간, block entry 시작

Static & Dynamic

  • Static: 컴파일 시간, link time
  • Dynamic: run time
  • 컴파일러 기반 언어는 인터프리터에 비해 효율적
    • 인터프리터는 매번 변수 사용할 때마다 공간 확인해야 함, 사용할 수 있는지 (실행해봐야 알 수 있음)
    • 컴파일러는 먼저 확인하고 지나감
  • Early binding times(컴파일)/ static: 미리 확인하고 넘어가기 때문에 더 효율적, 대부분 컴파일 언어
  • Later binding times(런타임)/ dynamic: 실행될 때마다 확인, 대부분 인터프리터 언어

Binding Time & Language Design

  • 유연성이 높음 → 객체지향
    • A a; A 상속 B
    • a= new A(); a = new B(); a.뭐시기 → 실제 객체는 A 클래스인지 B클래스인지는 실행할 때 알 수 있음 / 실행때 바인딩을 해줌
  • 실행되어야 알 수 있는 언어 존재
    • 파이썬은 타입 체크를 컴파일에 미룸
    • 다형성

상속 및 오버라이딩

Late Binding:

  • Parent c = new Child("child",2019);
    • override 된 자식의 getName() 덮어씌우기 때문 → run time에 이루어진다.

3.2 Object Lifetime and Storage Managements

  • Object(변수의 메모리 공간을 뜻함) Lifetime
  • 이름과, 실제 그 이름이 나타내는 object를 구별해야 함
  • key events
    1. 객체 생성과 소멸
    2. 바인딩 생성과 소멸
    3. 바인딩이 사라지고, 다시 살아남 (잠시 사용못하는 경우)
    4. 변수의 참조
  • Binding's lifetime & Object's lifetime
    • 바인딩이 만들어졌다가 소멸
    • 이 둘의 라이프 타임이 일치하지 않을 수도 있음
      • 같을 때
        //일치하다고 보는 경우
        void f() { //f함수가 실행할 때 a 변수 공간 할당 1. 오브젝트 생성
        	int a; //바인딩
        }
        //오브젝트, 바인딩 소멸
      • 다를 때 (객체 라이프 타임이 더 길다) → garbage
        //일치하지 않는 경우
        void f(int& x){
        	...
        } //x 바인딩은 해체
        int a = 2; //오브젝트 생성 및 바인딩
        f(a); //a 공간과 x의 공간 일치, x라는 이름의 바인딩 새로 생김
    • name-to-object binding이 object lifetime보다 길다
      • 코드 자체가 잘못됨
      • 간접적으로 바인딩(주소를 갖고 있는 것이므로)
      • 예시 → dangling reference
        • t의 주소는 담겨있지만 delete v 로 인해 object를 지우긴 했음
        • 객체는 사라졌지만 바인딩은 여전히 있음
    • object lifetime은 storage allocation mechanism 중 하나와 상응
      1. Static Object는 프로그램이 실행하는 동안 계속 남아있는 절대 주소(logical 의 절대를 의미함) : 전역 변수, data 영역
      2. Stack object: 함수가 실행할 때 사용되는 영역 (지역 변수)
      3. Heap object: 동적으로 할당되는 변수

3.2.1 Static Allocation

Static objects

  • 전역 변수, data 영역
  • static: static 변수의 경우 여러 번 호출시, 값이 변함
  • 하드 코딩된 것들 (numeric, string-valued constant literals 상수, 문자열)
  • 대부분의 컴파일러는 디버깅, 동적 타입 체크, 가비지 콜렉션 등을 테이블로 생성해서 저장 필요 → statical하게 할당
  • Statically allocated object란 프로그램 실행 중에 값이 바뀌면 안되며, 수정하지 못하게 read-only memory에 보호되어 할당됨

특징

  • 지역 변수들은 함수 호출시 생성되었다가 반환시 소멸 된다. (stack-based allocation)
  • Fortran: Recursion은 지원하지 않음 (stack 이 없었으니까)
    • 서브루틴 한 번만 호출 가능
    • 컴파일러는 지역 변수에 대해도 static 할당 가능 → (장점) 다른 함수 호출하는데 같은 영역 재사용 가능, run-time overhead(스택 관리시 발생하는/ 만들고 삭제 등등 )를 줄일 수 있음 (메모리 효율적)
  • 많은 언어에서 named constant는 컴파일 타임에 값이 결정되는 걸로 지정 → 이미 알려진 상수, 빌트인 함수, 산술 연산, 이미 정해진 값 정도만 사용
    • const int a = 2+3 : 컴파일시 계산 후 값 지정 (하드코딩)
    • cont int a = b+4; (b가 변수면 안됨, 알려져 있는 b라면 가능)
    • manifest constant or compile-time constants
    • 이미 값이 정해졌기에 static영역 사용
    • 지역변수인 것처럼 보여도 상수라면, stack에 넣지 않고 공유해서 쓰고자 하는 영역인 static에 저장
      void f(){
      	const int a = 3+4;
      	f();
      }
      
      //java
      String s = "abc";
      String s1 = "abc"; //한 곳에 만들어놓고 공유하기도 함
  • C언어/ Ada에서는 상수라고 하는 것은 변수이지만 값을 바꿀 수 없는 변수임 (상수 아님) → elaboration-time constant : stack
    • run time까지 알려지지 않은 다른 값에 의존적일 수 있음
      void f(int n){
      	const int a = n; //a는 n에 의존함 -> stack
      }
    • 파스칼은 진짜 상수임
    • C#: const(진짜 상수, compile-time), readonly(선언할때 or 생성자에서 값 지정, elaboration-time constants) 키워드 사용

3.2.2 Stack-Based Allocation

  • Recursion is allowed
    • 함수가 호출시 쌓이고, 리턴되면 값이 사라짐
  • frame, activation record: 한 개 함수가 호출되면서 쌓이는 영역
    • 매개변수, 지역변수, return values, 리턴 주소(Bookkeeping), 나를 부른 곳 등등
    • register: 빠른 메모리 공간, 이전에 사용하던 것들 값을 덮어 씌우면 안됨 → stack에 저장해 둠, 함수로 되돌아갈때 복원
    • callee에서 쉽게 찾을 수 있으므로 프레임의 맨 위로 올라갈 수 있음 (언어마다 다름)
  • 스택 관리: Calling sequence가 관리함
    • caller에 의해서 호출되기 직전과 직후에 실행되는 코드
      • f()에 값을 전달하고, 리턴 값 처리 등등
    • Prologue: 호출 됐을때, epilogue: 호출 끝났을 때
  • Stack Frame의 위치는 컴파일 타임때 알 수 없고 실행시 알 수 있다.
    • frame안의 object의 offset은 알 수 있음
    • stack pointer: 스택의 끝
    • frame pointer: 현재 실행되고 있는 함수의 activation record 어딘가를 가리키고 있음, D의 호출이 끝나면 스택에서 빼와서 변경 → 상대적인 위치로 지역 변수에 접근한다.
    • 지역 변수에 대한 내용은 오프셋을 파악하고 있기 때문에 이것을 기준으로 변수에 접근 가능
    • 지역 변수의 경우:일반적으로 negative offset
    • 리턴 값, 매개 변수: positive값 → sp 이용
      • 매개변수의 경우 caller에 있는게 좋음
  • Recursion이 없는 경우 → static 사용, 스택을 사용하는게 장점이 더 많음
  • stack 사용시 장점
    • 모든 서브 루틴이 동시에 호출되지 않음, 모든 서브 루틴의 공간을 할당해놓을 필요는 없음→ 적은 메모리 사용 가능 (효율적)
    • 재귀 가능

Heap-based Allocation

Heap

  • 실행 중에 할당, 해제 가능 → 동적 할당 공간
  • C++ → malloc , free / java → new
  • dynamically allocated data structures에 사용
    • String a = "abc" / a = "abcd" → heap이라고 볼 수 있음 (run time)
  • 공간, 속도 낭비를 고려해서 처리하는 방법 전략 세움
  • Internal Fragmentation → 블럭 크기 일정하다면 문제 심해짐
    • 필요한 메모리보다 큰 영역을 가져가서 나머지는 버림
  • External Fragmentation
    • 요청한 크기는 있지만 연속적이지 않음
    • 시간이 갈수록 원하는 크기의 메모리를 할당해주지 못할 수 있음
  • 사용되지 않는 메모리를 단일 연결 리스트로 관리
    • first fit: 크기와 상관없이 제일 먼저 나타나는 알고리즘 → 빠르다
    • best fit: 원하는 크기와 가장 크기가 비슷한 것 → 공간 낭비 줄여줌 → O(n)
    • 단일 연결
      • 요구된 것보다 더 큰 메모리를 선택할 때, 사용하는 공간, 사용되지 않는 공간나뉘어짐 (free list)
      • 연속적인 메모리를 합치는 경우도 있음

3.2.4 Garbage Collection

Heap-based object의 할당은 프로그램의 특정 연산자에 의해 일어남

  • 객체 생성 (new)
  • list.append()
  • 짧은 문자열을 가지고 있던 변수에 긴 문자열을 저장할때

→ 해제의 경우 프로그래머가 요청(C, C++, Rust): Explicit

  • Implicit 하게 처리 해줌 → Garbage Collection

Explicit Deallocation

  • 장점
    • 구현하기 쉬움
    • 실행 속도가 빠름
  • 단점
    • 에러 발생 (manual deallocation error)
    • object가 빨리 deallocate한다면 dangling reference(허상 포인터)
    • object가 deallocated되지 않으면 garbage, 공간 차지

Garbage Collection

  • 장점
    • 에러 없음
    • run time overhead 줄어듬
    • 최근에 복잡해져서 자동으로 정리해주는게 유용해짐
  • 단점
    • 언어 구현의 복잡성
    • 프로젝트 내에서 시간을 소비함 → 자동으로 처리하는 것을 포함시킴 (데이터 생성, 바인딩 내용)

3.3 Scope Rules

→ 변수, 함수의 사용 범위

Scope of a binding

  • a 변수와, a 변수 차지하는 공간 → data 영역(static int a=3;)과 이름 바인딩→ 바인딩이 유효한 영역

Statically scoped

  • compile time → 코드를 보면 알 수 있다.
  • 대부분의 현대 언어 (C, java, Python, C#)

Dynamically scoped

  • run time → 실행해봐야 알 수 있다.
  • 실해의 흐름에 따라 달라짐
  • APL, Snobol, Tcl

Scope

  • 바인딩이 변경되지 않는 코드상의 최대 영역
    • 적어도 바인딩이 소멸되지 않는 이상
  • 모듈의 바디, 클래스, 서브 루틴, if(){} 등 블럭

Referencing environment

  • 실행될 때 특정 순간에서 사용할 수 있는 바인딩
  • 변수, 전역 변수, 함수 등등

C 언어

  • 코드 블록 시작 → 새로운 스코프 만듦
  • 같은 이름을 사용하는 지역, 전역 변수 → 로컬에 대한 새로운 바인딩 만듦 (전역을 지역이 감춤) = 지역 변수를 우선시
  • 종료 → 바인딩 소멸, 전역 변수를 위한 바인딩이 보이도록

3.3.1 Static Scoping

Static scoping

  • 컴파일 때 결정되는 이름과 오브젝트 사이에서의 바인딩
  • Current binding: 가장 가까이 선언된 변수 사용
  • Early versions of Basic
    • 초보자위해서 만듦
    • 단일 스코프
    • 파이썬 처럼 a=3 처럼 쓰면 선언되는 것처럼 명백한 선언은 없음
  • pre-Fortran 90
    • 전역, 지역 변수
    • 지역 변수의 스코프는 서브 루틴 내에 제한
    • 만약 변수가 따로 선언되어 있지 않으면 현재 서브 루틴에 지역적으로 사용
      • 변수의 이름이 문자 I 부터 N까지 시작하면 integer, 아니면 real
    • 지역 변수: 함수 내, 한번 사용하고 사라지도록 됨
  • save를 사용해서 함수가 다시 실행되더라도 전에 실행했던 함수의 지역 변수 사용할 수 있도록 함
    • c의 static → 처음 0으로 초기화 → 함수가 여러 번 호출 되더라도 값은 유지
    • Algol의 own

3.3.2 Nested Subroutines

Nested Subroutines

: 함수 안에 또다른 함수

  • python, Lisp 지원, C언어 후계는 지원 안함
  • Algo-family: 특정 스코프에 정의되어 있는 상수, 변수, 함수는 스코프 밖에서는 모르도록 → 선언된 영역에서 사용
  • 같은 이름 사용 → 바깥은 감춤
  • active 변수 → 현재 위치로부터 가장 안쪽부터 찾음
  • built-in 함수 제공 (입출력): 가장 바깥에 있음 (전역 부분)
  • hole 존재 → 같은 이름
  • p1의 x를 f1에서 접근하지 못하지만, p1.x or p1::X와 같이 사용해서 접근 가능하도록 함 (Ada, C++)
  • lexically surrounding subroutines
  • 로컬 → frame pointer와 offset 사용
    • 전역변수는 아예 주소 정해져있어서 상관 없음
    • offset 벗어난다면 어떻게 사용?
    • 해당하는 프레임 찾아감 → 각각의 프레임 마다 부모에 해당하는 stack frame에 static link 걸어줌 null이 나올때까지 따라 올라가면 됨 k단계까지 내려감 → static link k개
    • k단계만큼 내려갔다 → k만큼 런타임에 링크
    • C → B → A (2번)

3.3.3 Declaration Order

블럭 b에 x 선언 → x의 스코프는 선언 이후부터 or 블록 전체?

  • 초기 언어: 모든 선언을 scope의 시작에 두도록 (Algol 60, Lisp)
  • 파스칼: 이름이 사용되기 전 선언 재귀 or subroutine 에서 유의해야 할 점 존재
    • N이 사용되었는지 확인하려면 블록안의 전체 내용 확인해야함
  • 전체를 유효 범위로 인식 → 선언 이후부터 인식으로 확장 (C, C++, Java, Ada)
  • C++, java에서 변수 선언을 늦게해도 되도록 함
    • 사용하기 전 define부터 해야한다는 것을 완화함
    • declare 사용전 사용 가능 → 같은 클래스 내부에만 있으면 어디서든 접근 가능
    • 클래스의 멤버는 모든 클래스의 메소드에서 사용가능
  • C# 함수 내에서는 오류 발생, 지역변수는 파스칼처럼 whole block scope 따름 클래스 멤버 변수는 해당안함 → 앞에서의 자바 예시가 적용이 됨
  • python: whole block variable declaration 자체가 없는 언어 ex) int x;
    • x=3 을 사용할 것 같은데 whole block 을 사용하므로 x=5가 S() 전체에 영향 미침 → 따라서 오류 발생 (선언 전, 값이 존재하지 않는 상태에서 사용했기 때문)
    • global 사용해서 해결

Declarations and Definitions

recursive type, subroutine: 사용되기 전에 선언되어야 함

  • extern(선언), intern 을 통해서 링크할때 찾아볼 수 있도록 해줌 → 사용하지 않으면 충돌 발생
  • ex) mutually recursive
    //Declaration -> return, function의 name, argument의 정보
    void g(); //있어야만 컴파일할 때 문제 없음 -> 선언, 정의 분리
    void f(){
    	g();
    }
    
    //Definition, 실제 구현한 부분 = 코드
    void g(){
    	f();
    }
    struct manager; /* declaration only */
    struct employee {
        struct manager* boss; 
        struct employee* next_employee;};
    struct manager { /* definition */
        struct employee* first_employee;};
    • employee 입장에서는 manager가 뒤에 있기 때문에 선언 부분 필요
    • mutually recursive → 상호 재귀적
void list_tail(follow_set fs);  /* declaration only */
void list(floow_set fs) { //declare, definition 동시에
    switch (input_token) {
        case id: match(id); list_tail(fs);}
void list_tail(follow_set fs) {  /* definition */
    switch (input_token) {
        case comma: match(comma); list(fs);}

Nested blocks

  • Algol60, C89(ANSI C), ada ⇒ 지역 변수 함수의 시작 부분에서 선언할 수 있음
    • ANSI C만 지원하는 컴파일러는 함수, 블럭 첫 부분에 선언해야함
  • C++, jaca, Algol 68, C99는 유연성 있게 어디서나 선언 가능, 해당 변수가 사용되기 전 선언되어야 함
  • 대부분 언어는 nested declaration은 outer declaration을 감춰줌
  • java, C#: static semantic error (outer declaration 이 현재 서브 루틴의 지역 변수라면)
    • 동일 함수 내에서 동일 이름으로 또 선언되면 에러 발생
  • c 언어 → 오류 발생하지 않음
  • 임시 선언 → lexically adjacent (바로 붙여서 사용 가능)
    • 코드가 너무 길다면 {} 써서 변수 선언 가능 → 프로그래밍이 쉬워짐
    • 블럭 안에만 임시로 사용해서 쓰게해 줌
    • 가독성 높임
    • 해당 코드가 다른 temp라는 이름을 가진 변수를 간섭할 가능성을 배제해줌
    • 일반 지역 변수와 라이프 타임이 비슷함 ⇒ 함수 실행할 때 생성, 함수 종료시 삭제

Modules

  • client이 몰라도 되는 내용을 숨김
    • 자동차 같은 경우, 운전하는 사람이 자동차 작동 방법은 알 필요가 없음
  • cognitive load: 머리로 생각해야 하는 부분 줄여줌
  • 인터페이스는 최대한 단순히, 내부 수정을 인터페이스에는 건드리지 말아야함
  • information hiding
    • 이해해야 하는 부분을 최소화하기 때문에 cognitive load (인지 부하) 줄여줌
    • 이름 충돌 위험 줄여줌
    • 데이터 추상화의 응집성을 통해서 데이터 보호할 수 있음 (데이터가 변경되지 않도록 하는 무결성 보장) → 데이터가 변경되지 않도록, 밖에 보이지 않으니까
    • compartmentalize: run time 에러 발생할 때 특정 클래스, 모듈 내로 한정 시켜줌

Encapsulating data and Subroutines

//nested subroutine -> 같은 라이프 타임 가짐
void f(){
	int b;
	void g(){
		int a;
	}
}
  • nested subroutine에 의해 제공되는 information hiding은 라이프 타임이 같음
    • g는 f가 살아있어야 사용 가능 → f와 같은 라이프 타임 사용
    • 지역 변수는 더 이상 메모리에 남아 있지 않는 문제 발생
  • Solution
    • save나 static을 사용함
      - 스코프는 함수 내지만 object 라이프 타임은 남아있음
      - static: 함수 내부가 스코프 영역
      - c언어에서 전역 static → 파일 내부만 사용 가능

      → 한 개 이상의 서브루틴으로 구성된 것에는 사용하지 못함, 다른 함수와 같이 사용하는 변수라면 의미가 없음

ex - pseudo-random number

  • 시드 넘버가 같으면 결국엔 반복되는 패턴임
  • 시드 넘버를 다르게 줘야함
  • 함수 - 함수 넘나들도록 : rand_int, set_seed 에만 해당하는 변수 설정하고자 함
  • Modules as Abstractions
    • 모듈은 서브루틴, 타입, 값 등의 객체를 encapsulate를 가능하게 함
    • 모듈 내의 함수는 서로 자유롭게 사용 가능
    • 모듈 안의 함수들은 모듈 밖에 보이면 안된다 (export될 때까지)
    • object의 접근성(사용 여부)에만 영향을 미치고 (모듈이 사용할 때만 object의 라이프 타임이 살아나고 등등 이런게 아님) 라이프 타임에는 영향을 미치지 않음
  • python - package, java - module, package, C C# PHP - namespace
  • C언어에서도 비슷하게 흉내 낼 수 있음 (static 함수 사용)
// Pseudorandom number generator module in C++
// seed 접근
#include <time.h>
namespace rand_mod { //c++에서 모듈
    unsigned int seed = time(0); 
    const unsigned int a = 48271;
    const unsigned int m = 0x7fffffff;
    void set_seed(unsigned int s) {
        seed = s; //seed
    }
    unsigned int rand_int() {
        return seed = (a * seed) % m; //랜덤이 다음의 Seed 역할 함
    }
}
  • namespace 내부에서 만들어진 name 바인딩은 밖에서 부분 으로 감춰짐 → 사라지는 것은 아님
  • C++: namespace는 전역보다 바깥에 위치해야 함(outermost)
  • set_seed 와 rand_int에 관계 없이 seed 값은 유지됨 rand_mod::set_seed 로 사용할 수 있음 (:: 속해 있다 → import의 의미로 쓴다)
  • c++ 에서 export, import(사용하는 곳) 없음
    • using rand_mod::rand_int 사용해서 이후부터 extern 없이 rand_int 사용 가능
    • using namespace rand_mod: rand_mod의 함수를 모두 사용한다
    • but 충돌 가능성 있음

Imports and Exports

  • 변수는 읽기 전용으로 export 될 수 있다
  • type - opaquely: 타입이 명확하게 알려지지 않은 export
    • 다른 것과 비교 가능, 수정안됨
  • Closed scopes
    • import 명시
  • Open scopes
    • import 하지 않아도 됨
  • Selectively open modules
    • rand_mod::set_seed와 같이 사용
  • import, export push, pop 사용
  • int, double 타입의 스택을 만들거다 → 모듈 안에 지정하면 그 타입 밖에 못 씀, 타입을 밖에서 지정해서 좀 더 유연성 있도록

Modules as Managers

  • 모듈은 추상화된 타입을 생성하는 것을 허용함. (= 서브 루틴에 Private 한 데이터 포함)
  • 스택의 배열의 공간 확보: 내부적으로 사용하는 것임
  • 단점: single abstraction만을 정의할 수 있음, 모듈 여러개 사용 못함
    • element 밖에 둬서 다른 타입을 element 사용 가능 → element 를 밖에서 지정 → 한 가지 종류의 스택만 생성 가능, 여러 개의 stack instance 생성 불가
  • Solution
    1. 모듈의 코드를 복사해서 다른 이름으로 새로 만듦 → stack2, real_stack 등등
    2. 매니저 개념으로 만들어야함
    • 구조체를 인스턴스화함
      • 원래 사용 방법
        void set_seed(unsigned int s) {
                seed = s; //seed
            }
      • C++에서 편법 써서 마치 모듈인 것처럼 취급 한 후 사용
    1. 모듈을 타입으로 지원하자
    • 클래스와 비슷
      • 클래스는 상속을 활용해서 기존의 클래스를 활용해 확장 함수를 만들 수 있음
      • 클래스는 다형성 지원
      • dynamic method dispatch: 부모의 함수를 호출하는 것 처럼 보이지만 자식의 함수 호출
    • 모듈 클래스 특징 비교
      • 모듈: client가 몰라도 되는 내용을 숨기며, 지역 변수 static으로 선언한다면 스코프가 함수로 한정되는 단점이 있어 서브 루틴 간의 값을 공유하지 못한다. 이의 단점을 보완하기 위해 모듈이라는 개념이 등장하게 되었다.

Modules Containing Classes

  • 기존의 클래스를 아우르는 모듈 개념 필요

  • 하나로 클래스를 묶어서 하기에는 큰 프로그램을 위한 모듈 필요

  • 자바의 모듈

    • 패키지들을 묶어서 추상화시켜 관리할 수 있는 방법

      • 패키지는 관련있는 클래스를 묶어서 관리

      • private, public, protected 등 가시성 부여 → 내부, 외부 사용할 수 있는 클래스 구별

      • 패키지의 특성이 추상화, 캡슐화를 해침

        웹 브라우저를 위한 패키지 → public으로 만듦 → 다른 곳에서도 사용 가능

        sun: 우리만 쓰려고 만들었는데 다들 사용하게 됨 → 내부적으로 쓰려고 해도 내부적으로 못씀 (protected: 패키지를 넘어가면 사용할 수 없음)

        패키지들의 public 클래스들이 모두에게 공개되는 것을 막음

        module 안에 패키지가 들어감

      • 이 모듈안에 있는 패키지를 제외해서 export 하지 못함

  • 기존 패키지 대비 모듈의 장점 (java 모듈 제공, 패키지 단위)

    • 일부는 export, 일부는 import
    • public 클래스를 숨길 수 있으므로 강한 캡슐화 지원
    • 모듈 단위로 추상화, 캡슐화를 지원함으로써 패키지 간의 관계를 모듈 단위로 정리할 수 있어 복잡한 의존성을 줄일 수 있음
    • 모듈은 컴파일된 자바 코드 외에 이미지 파일이나 xml파일 같은 다른 리소스 파일들을 포함시킬 수 있음
    • 응용 프로그램을 모듈에 넣는 것보다 자주 사용될 수 잇는 라이브러리를 구축할 때 유용함

3.3.6 Dynamic Scoping

  • 실행에 따라 달라짐
  • 가장 최근에 마주친것을 current binding
  • 인터프리터 방식을 채택하는 경우가 많음
  • Static Scoping VS Dynamic Scoping
    • static: 해당 변수가 스코프 내에 없을 때 가장 가까운 바깥쪽 부터
    • Dynamic: 실행 중에 만났던 가장 최근의 변수 (실행되는 스코프에서 리턴되면서 사라지지 않은 상태의 변수여야 함) (APL, Snobol, Tcl, TEX, early dialects of Lisp, Perl)
    • dynamic의 second()의 int n을 1로 바꿈
      • second() 함수의 지역변수는 1로 바꼈다가 리턴되면서 사라지므로, 전역 변수 n=2가 된다
      • first()는 전역 변수 1로 바꿈
    • 가장 가까운 double max_score를 가져감
    • 타입이 안맞는 경우가 발생할 수도 → type crash

Implementing Scope

  • statically scoped program에서 compiler는 symbol table을 만듦
    • 맵으로 변수, 값 저장
  • a name-to object-binding: 새로운 매핑 추가
  • look up: 저장된 이름 조회
    • stastic(compile) - stack 사용 (enter_scope, leave_scope) → 가장 위에 있는 a
    • dynamic(interpreter) - 최근이용
profile
💻 ☕️ 🏝 🍑 🍹 🏊‍♀️

0개의 댓글