UFCS 로 줄여부르는 연쇄 함수 호출 문법 은 D 언어의 핵심 기능 중 하나이자, 코드 재사용성(code reusability)과 확장가능성(scalability)을 실현하는 요소입니다.
UFCS를 사용하면 어떤 함수라도 fun(a)
형태로 호출하던 함수를 a.fun()
형태로 호출할 수 있습니다. 약간 어색할 수 있습니다. 만약 값 a
의 원본 타입에 fun()
이라는 내부 함수가 정의되어있지 않다면, D 언어는 해당 프로그램 전역에 이용 가능한 함수 중 fun
이라는 이름을 가지면서 a
타입의 값을 받을 수 있는 함수를 찾아서 적용합니다.
이 문법은 특히 복잡한 함수 호출이 이어질 때, 가독성을 향상시킬 수 있습니다.
foo(bar(a))
이런 일반적 호출을 아래와 같이 바꿔쓰는 게 가능합니다.
a.bar().foo()
게다가 D 언어에서 입력값이 필요 없는 함수는 소괄호 ( )
조차 생략이 가능합니다. 프로퍼티(property)에 대해 언급하며 한번 간단히 설명한 적이 있습니다. 다시 정리하자면, 소괄호를 생략함으로써 함수를 마치 프로퍼티처럼 다룰 수 있게 되는 것입니다.
import std.uni : toLower;
"D rocks".toLower; // toLower는 함수이지만 마치 프로퍼티처럼 쓰입니다. 결과물은 "d rocks" 입니다.
UFCS는 범위 탐색(range) 를 다루는 동안 여러 알고리즘 함수를 적용해야할 때도 유용하게 쓰입니다.
import std.algorithm : group;
import std.range : chain, retro, front, retro;
// chain() 을 먼저 적용해 [1, 2, 3, 4]를 만듭니다.
// 다음에 retro([1, 2, 3, 4]) 를 적용해 [4, 3, 2, 1]을 얻습니다.
[1, 2].chain([3, 4]).retro; // 4, 3, 2, 1
// front(dropOne(group([1, 1, 2, 2, 2]))) 로 다시 고쳐쓸 수 있습니다만,
// UFCS의 연쇄 호출 형태가 좀 더 예쁩니다.
[1, 1, 2, 2, 2].group.dropOne.front; // tuple(2, 3u)
std.range