Tcl의 네임스페이스 (Namespace)

admin의 아바타

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}