명명 된 매개 변수를 사용하면 코드를 읽기 쉽고 쓰기 어렵게 만듭니다.
코드를 읽을 때 명명 된 매개 변수는 코드를 이해하기 쉽게 만드는 컨텍스트를 도입 할 수 있습니다. 예를 들어이 생성자를 고려하십시오 Color(1, 102, 205, 170)
. 지구상에서 무슨 의미입니까? 실제로, Color(alpha: 1, red: 102, green: 205, blue: 170)
읽기가 훨씬 쉬울 것입니다. 그러나 아아, 컴파일러는 "아니오"를 말한다 - 그것은 원한다 Color(a: 1, r: 102, g: 205, b: 170)
. 명명 된 매개 변수를 사용하여 코드를 작성할 때 정확한 이름을 찾는 데 불필요한 시간을 소비합니다. 순서를 잊어 버리는 것보다 일부 매개 변수의 정확한 이름을 잊는 것이 더 쉽습니다.
DateTime
거의 동일한 인터페이스로 포인트와 지속 시간에 두 개의 형제 클래스가 있는 API를 사용할 때 한 번 물었습니다 . DateTime->new(...)
허용되는 동안second => 30
인수의 DateTime::Duration->new(...)
원 seconds => 30
및 기타 장치에 대한 유사. 그렇습니다, 그것은 절대적으로 의미가 있지만, 이것은 명명 된 매개 변수 ≠ 사용의 용이함을 보여주었습니다.
나쁜 이름도 읽기가 쉽지 않습니다
명명 된 매개 변수가 나쁜 방법의 또 다른 예는 아마도 R 언어 일 것입니다 . 이 코드는 데이터 플롯을 만듭니다.
plot(plotdata$n, plotdata$mu, type="p", pch=17, lty=1, bty="n", ann=FALSE, axes=FALSE)
x 및 y 데이터 행에 대한 두 개의 위치 인수 와 이름 지정된 매개 변수 목록이 표시됩니다. 기본값에는 더 많은 옵션이 있으며 기본값을 변경하거나 명시 적으로 지정하려는 옵션 만 나열됩니다. 이 코드가 매직 넘버를 사용한다는 것을 무시하고 열거 형 (R이 있다면!)을 사용하면 이점을 얻을 수 있습니다.
pch
실제로는 모든 데이터 포인트에 대해 그려지는 그림 문자 인 그림 문자입니다. 17
빈 원 또는 이와 비슷한 것입니다.
lty
선 종류입니다. 여기에 1
실선이다.
bty
박스 타입입니다. "n"
플롯 주위에 상자가 그려지지 않도록 설정합니다 .
ann
축 주석의 모양을 제어합니다.
각 약어의 의미를 모르는 사람에게는 이러한 옵션이 다소 혼동됩니다. 또한 R이 이러한 레이블을 사용하는 이유를 밝힙니다. 자체 문서화 코드가 아니라 값을 올바른 변수에 매핑하기위한 키로 (동적 형식 언어).
매개 변수 및 서명의 속성
함수 서명에는 다음과 같은 속성이있을 수 있습니다.
- 인수는 순서가 있거나 순서가 없을 수 있습니다.
- 명명되거나 명명되지 않은,
- 필수 또는 선택.
- 서명은 크기 나 유형별로 오버로드 될 수 있습니다.
- varargs로 지정되지 않은 크기를 가질 수 있습니다.
다른 언어는이 시스템의 다른 좌표에 위치합니다. C에서 인수는 순서가 지정되고 이름이 지정되지 않으며 항상 필요하며 varargs 일 수 있습니다. Java에서는 서명이 오버로드 될 수 있다는 점을 제외하면 상황이 유사합니다. Objective C에서 서명은 주문, 이름 지정, 필수이며 C 주변의 구문 설탕이므로 오버로드 할 수 없습니다.
varargs (명령 줄 인터페이스, Perl,…)가있는 동적 유형 언어는 선택적 명명 된 매개 변수를 에뮬레이션 할 수 있습니다. 서명 크기가 오버로드 된 언어에는 위치 선택적 매개 변수와 같은 것이 있습니다.
명명 된 매개 변수를 구현하지 않는 방법
명명 된 매개 변수를 생각할 때 일반적으로 명명 된 선택적, 정렬되지 않은 매개 변수를 가정합니다. 이를 구현하는 것은 어렵다.
선택적 매개 변수는 기본값을 가질 수 있습니다. 이들은 호출 된 함수에 의해 지정되어야하며 호출 코드로 컴파일되어서는 안됩니다. 그렇지 않으면 모든 종속 코드를 다시 컴파일하지 않고 기본값을 업데이트 할 수 없습니다.
이제 중요한 질문은 인수가 실제로 함수에 전달되는 방법입니다. 정렬 된 매개 변수를 사용하면 arg를 레지스터 또는 스택에서 고유 한 순서로 전달할 수 있습니다. 레지스터를 잠시 제외시킬 때 문제는 정렬되지 않은 선택적 인수를 스택에 넣는 방법입니다.
이를 위해서는 선택적 인수보다 순서가 필요합니다. 선언 코드가 변경되면 어떻게됩니까? 순서는 관련이 없으므로 함수 선언에서 재정렬하면 스택에서 값의 위치가 변경되지 않아야합니다. 새로운 선택적 매개 변수를 추가 할 수 있는지 고려해야합니다. 이전에는 해당 매개 변수를 사용하지 않은 코드가 여전히 새 매개 변수와 함께 작동해야하므로 사용자 관점에서 이것은 그렇게 보입니다. 따라서 선언에서 주문을 사용하거나 알파벳 순서를 사용하는 것과 같은 주문은 제외됩니다.
서브 타이핑과 Liskov 대체 원칙에 비추어 이것을 고려하십시오 – 컴파일 된 출력에서, 동일한 명령어는 아마도 새로운 명명 된 매개 변수를 가진 서브 타입과 수퍼 타입에서 메소드를 호출 할 수 있어야합니다.
가능한 구현
결정적인 순서를 가질 수 없다면 순서없는 데이터 구조가 필요합니다.
가장 간단한 구현은 매개 변수 이름과 값을 전달하는 것입니다. Perl에서 또는 명령 행 도구를 사용하여 명명 된 매개 변수를 에뮬레이트하는 방법입니다. 이렇게하면 위에서 언급 한 모든 확장 문제를 해결할 수 있지만 성능에 중요한 코드의 옵션이 아닌 공간 낭비가 클 수 있습니다. 또한 이러한 명명 된 매개 변수를 처리하는 것은 단순히 스택에서 값을 팝하는 것보다 훨씬 복잡합니다.
실제로 문자열 풀링을 사용하여 공간 요구 사항을 줄일 수 있습니다.이 경우 문자열 비교는 포인터 비교에 대한 이후의 문자열 비교를 줄일 수 있습니다 (정적 문자열이 실제로 풀링되는 것을 보장 할 수없는 경우에는 두 문자열을 비교해야합니다). 세부 묘사).
대신 명명 된 인수의 사전으로 작동하는 영리한 데이터 구조를 전달할 수도 있습니다. 키 세트가 정적으로 호출 위치에 알려지기 때문에 호출자 측에서 저렴합니다. 이를 통해 완벽한 해시 함수를 만들거나 트라이를 미리 계산할 수 있습니다. 수신자는 여전히 다소 비싼 모든 가능한 매개 변수 이름이 있는지 테스트해야합니다. 이와 같은 것이 Python에서 사용됩니다.
대부분의 경우 너무 비쌉니다.
명명 된 매개 변수가있는 함수를 올바르게 확장 할 수있는 경우 명확한 순서를 가정 할 수 없습니다. 따라서 두 가지 솔루션 만 있습니다.
- 명명 된 매개 변수의 순서를 서명의 일부로 만들고 나중에 변경을 허용하지 마십시오. 이것은 자체 문서화 코드에는 유용하지만 선택적 인수에는 도움이되지 않습니다.
- 키-값 데이터 구조를 수신자에게 전달하면 유용한 정보를 추출해야합니다. 이것은 비교가 매우 비싸고, 성능에 중점을 두지 않고 스크립팅 언어에서만 볼 수 있습니다.
다른 함정
함수 선언의 변수 이름은 일반적으로 내부적으로 의미가 있으며 많은 문서 도구가 여전히 표시하더라도 인터페이스의 일부가 아닙니다. 많은 경우 내부 변수와 해당 명명 된 인수에 다른 이름을 원할 것입니다. 명명 된 매개 변수의 외부에서 볼 수있는 이름을 선택할 수없는 언어는 변수 이름이 호출 컨텍스트를 염두에두고 사용되지 않으면 많은 것을 얻지 못합니다.
명명 된 인수의 에뮬레이션 문제는 호출자 측에서 정적 검사가 부족하다는 것입니다. 인수 사전을 전달할 때 (Python을 보면) 잊어 버리기가 특히 쉽습니다. 사전을 전달하는 것이 일반적인 해결 방법 (예 : JavaScript)이기 때문에 중요합니다.foo({bar: "baz", qux: 42})
합니다. 여기서는 값의 유형이나 특정 이름의 존재 또는 부재를 정적으로 확인할 수 없습니다.
명명 된 매개 변수 에뮬레이션 (정적으로 형식화 된 언어)
문자열을 키로 사용하고 객체를 값으로 사용하는 것은 정적 유형 검사기에는 유용하지 않습니다. 그러나 명명 된 인수는 구조체 또는 객체 리터럴로 에뮬레이션 할 수 있습니다.
// Java
static abstract class Arguments {
public String bar = "default";
public int qux = 0;
}
void foo(Arguments args) {
...
}
/* using an initializer block */
foo(new Arguments(){{ bar = "baz"; qux = 42; }});