본문으로 바로가기

Tcl의 네임스페이스 (Namespace)

category 카테고리 없음 2024. 4. 12. 17:11

namespace는 패키지 사이의 심볼(변수와 프로시져)의 충돌을 피하기 위한 기능입니다. 오브젝트 지향과 비슷하게 변수와 프로시져를 연결시키는데도 사용할 수 있습니다. 하지만 클래스와 비슷해 보이지만, 클래스 정도의 기능은 가지고 있지 않습니다. 클래스를 사용하기 위해서는 incr Tcl 확장을 사용할 필요가 있습니다. 그렇다면, namespace의 간단한 예를 설명합니다.

변수와 프로시져

아래는 Hello라고 하는 namespace에 변수 var과 프로시져 print가 정의되고 있습니다. 변수 var과 프로시져 print는 global 스코프나 다른 namespace로 정의된 것과는 충돌하지 않습니다.

namespace eval Hello {
   variable var {Hello World}
 
   proc print {} {
      variable var
      puts $var
   }
}
 
namespace eval Hello {
   variable var {Hello World}
}
 
proc Hello::print {} {
   variable var
   puts $var
}


namespace의 변수와 프로시져는 namespace이름과 스코프 해결연산자(::)를 사용하여 엑세스 합니다.

puts $Hello::var
=>Hello World
Hello::print
=>Hello World

export와 import

아래도 Hello라는 이름의 namespace에 변수 var과, 프로시져 print가 정의되고 있습니다. namespace의 프로시져는 export 선언을 하면, namespace 이름을 생략하고 호출할 수 있습니다.

namespace eval Hello {
   variable var {Hello World}
 
   namespace export print
 
   proc print {} {
      variable var
      puts $var
   }
}


호출 측은 import선언을 할 필요가 있습니다. import로 프로시져 이름에 *를 주어지면 모든 프로시져에 매치됩니다.

namespace import Hello::print
print
=>Hello World
 
namespace import Hello::*
print
=>Hello World

스코프(Scope)

Tcl은, 이벤트 핸들러를 사용하여 커맨드를 실행할 수 있습니다. after커맨드, bind커맨드, button -command 커맨드 등이 이에 해당합니다. 이벤트핸들러는 global 스코프에서 실행된다는 점의 주의하셔야 합니다. 예를 들면, 아래의 소스는 after로 1초 후에 실행이 됩니다. 하지만 커맨드가 실행된 것은 global 스코프이므로, 변수 var가 정의되어 있지 않다고 에러가 뜹니다.

namespace eval Hello {
   variable var {Hello World}
 
   proc print {} {
      variable var
      after 1000 {puts $var}
   }
}

Hello::print


해결책으로서는, code 커맨드로 namespace를 사전에 해결한 코드를 생성해 내는 방법입니다.

namespace eval Hello {
   variable var {Hello World}
 
   proc print {} {
      set cmd [namespace code {puts $var}]
      after 1000 $cmd
   }
}
Hello::print


이때 사전에 해결한 코드($cmd 변수의 내용)는 아래처럼 됩니다. inscope 커맨드는, 지정된 namespace로 인자의 커맨드를 실행합니다.

namespace inscope ::Hello {puts $var}