proc — Tcl 프로시저 만들기

proc — Tcl 프로시저 만들기

Tcl에서 반복해서 쓰는 로직이 생기면, 절차(procedure)로 묶어두고 이름을 붙이는 게 편해요. proc 명령이 바로 그 역할을 하는데요, 기존에 같은 이름의 명령이나 프로시저가 있으면 그걸 새 것으로 교체해요. 처음 프로시저를 만들 때 익혀 두면, 인수 처리와 반환값 동작을 자연스럽게 이해할 수 있어요.

출처: Tcl Commands — proc

본문

proc name args body

proc 명령은 name이라는 새 Tcl 프로시저를 만들어요. 그 이름으로 이미 존재하던 명령이나 프로시저가 있다면 교체됩니다. 새 명령이 호출될 때마다 body의 내용이 Tcl 인터프리터에 의해 실행돼요.

보통 name은 정규화되지 않은 이름(네임스페이스 이름을 포함하지 않는 이름)이고, 그러면 새 프로시저는 현재 네임스페이스에 만들어져요. name에 네임스페이스 한정자가 포함되어 있으면, 해당 네임스페이스에 프로시저가 생성됩니다.

args는 프로시저의 형식 인수(formal arguments)를 지정해요. 리스트(비어 있을 수도 있어요)로 되어 있고, 각 원소가 인수 하나를 나타내요. 각 인수 지정자도 하나 또는 두 개의 필드를 가진 리스트예요. 필드가 하나뿐이면 그게 인수 이름이고, 필드가 두 개면 첫 번째가 인수 이름, 두 번째가 기본값(default value)이에요.

기본값을 가진 인수 뒤에 기본값이 없는 인수가 오면, 그 기본값 인수는 필수 인수가 돼요. 마지막 필수 형식 인수까지 포함해 모든 인수에 값이 채워질 만큼 충분한 실인수(actual arguments)가 제공되어야 해요.

name이 호출되면 각 형식 인수에 대해 지역 변수(local variable)가 생성돼요. 그 값은 호출 명령에서 대응하는 인수의 값, 또는 인수의 기본값이에요. 실인수는 형식 인수에 엄격히 순서대로 배정돼요.

기본값이 있는 인수는 프로시저 호출에서 생략할 수 있어요. 하지만 기본값이 없는 모든 형식 인수에 대해 충분한 실인수가 있어야 하고, 초과하는 실인수가 있어서는 안 돼요.

기본값을 가진 인수 뒤에 기본값이 없는 인수가 따라오면 그 인수는 사실상 필수 인수가 됩니다. 이것은 Tcl의 향후 버전에서 바뀔 수도 있어요. 그러니 이식 가능한 코드는 모든 선택 인수가 모든 필수 인수 뒤에 오도록 작성하는 게 좋아요.

가변 개수의 인수를 가진 프로시저를 허용하는 특별한 경우가 하나 있어요. 마지막 형식 인수의 이름이 args라면, 프로시저 호출이 형식 인수보다 더 많은 실인수를 포함할 수 있어요. 이 경우 args에 배정될 인수부터 시작하는 모든 실인수가 하나의 리스트로 합쳐지고(list 명령을 쓴 것처럼), 이 합쳐진 값이 지역 변수 args에 배정돼요.

body가 실행되는 동안 변수 이름은 보통 지역 변수를 가리켜요. 지역 변수는 참조될 때 자동으로 생성되고, 프로시저가 반환될 때 삭제돼요. 각 인수에 대해 지역 변수가 하나씩 자동으로 생성돼요. 다른 변수는 global, variable, upvar, namespace upvar 명령 중 하나를 호출해야만 접근할 수 있어요. body가 실행될 때의 현재 네임스페이스는 프로시저 이름이 존재하는 네임스페이스예요. 즉, rename으로 바꾸지 않는 한 프로시저가 만들어진 네임스페이스가 그대로예요.

proc 명령은 빈 문자열을 반환해요. 프로시저가 호출되면, 프로시저의 반환값은 return 명령에 지정된 값이에요. 프로시저가 명시적인 return을 실행하지 않으면, 반환값은 프로시저 본문에서 마지막으로 실행된 명령의 값이에요. 프로시저 본문 실행 중 오류가 발생하면, 프로시저 전체가 그 오류를 그대로 반환해요.

예제

두 인수를 받아 그 합과 곱을 모두 출력하는 프로시저예요. 그리고 호출한 쪽에 문자열 "OK"를 명시적 결과로 돌려줘요.

proc printSumProduct {x y} {
    set sum [expr {$x + $y}]
    set prod [expr {$x * $y}]
    puts "sum is $sum, product is $prod"
    return "OK"
}

인수를 몇 개 받든 상관없이 하나씩 출력하는 프로시저예요.

proc printArguments args {
    foreach arg $args {
        puts $arg
    }
}

이 프로시저는 incr 명령과 비슷한데, 이름 붙은 변수의 내용을 값(multiplier, 기본값 2)과 곱해요.

proc mult {varName {multiplier 2}} {
    upvar 1 $varName var
    set var [expr {$var * $multiplier}]
}

더 알아보기

  • info — 인터프리터와 프로시저에 대한 정보를 조회해요
  • unknown — 알 수 없는 명령이 호출될 때 동작을 정의해요