return — 프로시저에서 반환, 또는 스크립트의 반환 코드 설정

return — 프로시저에서 반환, 또는 스크립트의 반환 코드 설정

프로시저가 작업을 마치고 호출자에게 결과를 돌려주는 명령이 바로 return이에요. 단순히 값을 반환하는 것이 전부가 아니라, 오류나 break/continue 같은 특별한 반환 코드를 만들어 내는 데도 쓰여요. Tcl에서 프로그램의 흐름을 제어하는 핵심 개념 가운데 하나예요.

출처: 문서

본문

문법

return ?result?
return ?-code code? ?result?
return ?option value ...? ?result?

동작 방식

가장 간단한 사용법에서 return은 프로시저 본문에서 옵션 없이 사용돼 프로시저의 호출자에게 즉시 제어권을 돌려줘요. result 인자가 주어지면 그 값이 호출자에게 전달되는 프로시저의 결과가 돼요. result가 지정되지 않으면 빈 문자열이 프로시저의 결과로 호출자에게 반환돼요.

returnsource 명령이 평가하는 스크립트 파일 안에서도 비슷한 기능을 해요. source가 파일 내용을 스크립트로 평가할 때 return 호출은 스크립트 평가를 즉시 중단시키고, result 값(또는 빈 문자열)이 source 명령의 결과로 반환돼요.

특수 반환 코드(EXCEPTIONAL RETURN CODES)

프로시저의 결과뿐 아니라 프로시저의 반환 코드도 -code 옵션을 통해 return으로 설정할 수 있어요. 보통 -code 옵션을 지정하지 않으면 프로시저는 정상적으로 반환해요. 하지만 -code 옵션으로 프로시저에서 특수한 반환을 만들어 낼 수 있어요.

code는 다음 값 중 하나일 수 있어요:

  • ok (또는 0) — 정상 반환: 옵션을 생략한 것과 같음. 반환 코드는 0 (TCL_OK).
  • error (또는 1) — 오류 반환: 반환 코드는 1 (TCL_ERROR). 프로시저 명령은 호출 문맥에서 error 명령의 결과처럼 동작해요.
  • return (또는 2) — 반환 코드는 2 (TCL_RETURN). 프로시저 명령은 호출 문맥에서 인자 없는 return 명령처럼 동작해요.
  • break (또는 3) — 반환 코드는 3 (TCL_BREAK). 호출 문맥에서 break 명령처럼 동작해요.
  • continue (또는 4) — 반환 코드는 4 (TCL_CONTINUE). 호출 문맥에서 continue 명령처럼 동작해요.
  • valuevalue는 정수여야 하며 현재 프로시저의 반환 코드로 반환돼요.

프로시저가 호출자로부터 잘못된 인자를 받았음을 알리고 싶으면 result를 적절한 오류 메시지로 설정한 return -code error를 사용할 수 있어요. 그 외에는 return -code 옵션의 사용은 대부분 새 제어 구조를 구현하는 프로시저로 제한돼요.

반환 옵션(RETURN OPTIONS)

결과와 반환 코드 외에도 Tcl에서 명령 평가는 반환 옵션 딕셔너리(return options dictionary)를 생성해요. 일반적인 사용에서 return에 인자로 주어진 모든 옵션-값 쌍은 이 딕셔너리의 항목이 되고, 아래에 명시된 경우를 제외하면 어떤 값이든 허용돼요. catch 명령으로 스크립트 평가에서 비롯된 반환 코드, 결과, 반환 옵션 딕셔너리 등 이 모든 정보를 포착할 수 있어요.

Tcl이 특별히 인식해 처리하는 다른 반환 옵션은 다음과 같아요:

  • -errorcode list-code 옵션의 값이 TCL_ERROR일 때만 특별 처리를 받아요. 그때 list 값은 오류에 대한 추가 정보로, 프로그램이 추가 처리할 수 있도록 Tcl 리스트로 제공돼요. -code error 옵션이 주어질 때 return-errorcode 옵션이 없으면 반환 옵션 딕셔너리의 -errorcode 항목 값이 기본값 NONE으로 설정돼요. -errorcode 반환 옵션은 전역 변수 errorCode에도 저장돼요.
  • -errorinfo info-code 값이 TCL_ERROR일 때만 특별 처리. info는 초기 스택 트레이스로, 오류가 발생한 문맥에 대한 추가 정보를 인간 독자에게 제공하기 위한 것이에요. 스택 트레이스는 전역 변수 errorInfo에도 저장돼요. -code error가 주어질 때 -errorinfo가 없으면 Tcl이 자신의 초기 스택 트레이스 값을 -errorinfo 항목에 제공해요.
  • -errorstack list-code 값이 TCL_ERROR일 때만 특별 처리. list는 초기 오류 스택으로, 각 proc 레벨에 전달된 실제 인자 값을 기록해요. 오류 스택은 info errorstack으로도 접근할 수 있어요.
  • -level level-level-code 옵션은 함께 동작해, 현재 평가 중인 명령 중 하나가 반환할 반환 코드를 설정해요. level 값은 호출 스택의 레벨 수를 나타내는 비음의 정수여야 해요. 현재 평가 중인 명령의 반환 코드가 code여야 하는 스택 위의 레벨 수를 정의해요. -level이 없으면 기본값은 1로, return이 현재 프로시저가 그 호출자(호출 스택 1레벨 위)에게 반환하는 반환 코드를 설정해요.
  • -options optionsoptions 값은 유효한 딕셔너리여야 해요. 그 딕셔너리의 항목들은 return 명령에 대한 추가 옵션-값 쌍으로 취급돼요.

반환 코드 처리 메커니즘(RETURN CODE HANDLING MECHANISMS)

Tcl에서 반환 코드는 프로그램 흐름을 제어하는 데 사용돼요. Tcl 스크립트는 Tcl 명령의 시퀀스예요. 각 명령 평가가 TCL_OK 반환 코드를 반환하는 한 평가는 스크립트의 다음 명령으로 계속돼요. 명령 평가가 반환한 특수 반환 코드(비-TCL_OK)는 다음 명령으로의 흐름을 중단시켜요. 스크립트 평가가 중단되고, 명령의 특수 반환 코드가 전체 스크립트 평가의 반환 코드가 돼요. 이것이 스크립트 평가 중 오류가 중단과 호출 스택의 풀림(unwinding)을 일으키는 메커니즘이에요. break, continue, return 같은 명령이 모든 명령을 순서대로 평가하지 않고 스크립트 평가를 종료시키는 메커니즘이기도 해요.

Tcl의 내장 명령 중 일부는 기능의 일부로 스크립트를 평가해요. 이 명령들은 특수 반환 코드를 활용해 특별한 기능을 가능하게 해요. 예를 들어 while, for, foreach 같은 루프를 제공하는 내장 Tcl 명령은 루프의 본문인 스크립트를 평가해요. 루프 본문 평가가 TCL_BREAK나 TCL_CONTINUE 반환 코드를 반환하면, 루프 명령은 breakcontinue 명령이 루프에서 갖는 문서화된 해석을 제공하도록 반응할 수 있어요.

프로시저 호출도 스크립트(프로시저 본문)의 평가를 수반해요. 프로시저 호출은 프로시저 본문 평가가 TCL_RETURN 반환 코드를 반환할 때 특별 처리를 제공해요. 그 상황에서 반환 옵션 딕셔너리의 -level 항목이 감소돼요. 감소 후 -level 값이 0이면 -code 항목의 값이 프로시저의 반환 코드가 돼요. 감소 후 -level 값이 여전히 0보다 크면 프로시저의 반환 코드는 TCL_RETURN이에요. 프로시저 호출이 다른 프로시저의 본문 평가 중 일어났다면, 이 과정은 호출 스택 위로 반복되며 각 레벨에서 -level 값을 감소시켜, code가 호출 스택 위 level 레벨 위의 현재 명령 레벨의 반환 코드가 되게 해요. source 명령도 TCL_RETURN 반환 코드에 대해 같은 처리를 수행해요.

return 명령 자체의 반환 코드가 프로시저 호출에 의한 이 특별 처리를 촉발해요. return-level 0 옵션이 주어지면 return 명령 자체의 반환 코드가 -code 옵션의 값(기본값 TCL_OK)이 돼요. -level 옵션의 다른 값(기본값 1 포함)은 return 명령 자체의 반환 코드가 TCL_RETURN이 되게 해, 둘러싼 프로시저에서의 반환을 촉발해요.

예제

return으로 프로시저에서 반환해 프로시저 본문을 중단시키는 간단한 예:

proc printOneLine {} {
    puts "line 1" ;# 이 줄은 출력됨
    return
    puts "line 2" ;# 이 줄은 출력되지 않음
}

return으로 프로시저가 반환하는 값을 설정하는 예:

proc returnX {} {return X}
puts [returnX] ;# "X" 출력

return -code error로 잘못된 인자를 보고하는 더 완전한 예:

proc factorial {n} {
    if {![string is integer $n] || ($n < 0)} {
        return -code error \
            "expected non-negative integer,\
            but got \"$n\""
    }
    if {$n < 2} {
        return 1
    }
    set factor [factorial [expr {$n - 1}]]
    set product [expr {$n * $factor}]
    return $product
}

break를 대체하는 프로시저:

proc myBreak {} {
    return -code break
}

-level 0 옵션으로 return 자체가 interp alias의 도움으로 break를 대체할 수 있어요:

interp alias {} Break {} return -level 0 -code break

catchreturn -options로 잡은 오류를 다시 던지는 예:

proc doSomething {} {
    set resource [allocate]
    catch {
        # 오류를 일으킬 수 있는 긴 연산 스크립트
    } result options
    deallocate $resource
    return -options $options $result
}

마지막으로 반환 옵션을 고급으로 사용해 return 자체를 대체하는 프로시저를 만드는 예:

proc myReturn {args} {
    set result ""
    if {[llength $args] % 2} {
        set result [lindex $args end]
        set args [lrange $args 0 end-1]
    }
    set options [dict merge {-level 1} $args]
    dict incr options -level
    return -options $options $result
}

더 알아보기

  • break, continue: 루프 제어
  • catch, error, errorCode, errorInfo: 오류 처리
  • proc, source: 프로시저와 스크립트 평가
  • throw, try: 예외 처리 확장