Perl 5의 기능 프로토 타입이 왜 나쁜가요?


116

다른 Stack Overflow 질문에서 Leon Timmermans는 다음과 같이 주장했습니다.

프로토 타입을 사용하지 말라고 조언합니다. 그들은 그들의 용도가 있지만 대부분의 경우는 아니며 확실히 이것에는 없습니다.

왜 이것이 사실일까요? 나는 거의 항상 내 Perl 기능을위한 프로토 타입을 제공하고 있으며, 다른 사람이 그것들을 사용하는 것에 대해 나쁜 말을하는 것을 본 적이 없습니다.


나도 궁금해. 내가 사용하지 않는 유일한 경우는 가변 개수의 인수로 호출 할 때입니다.
Paul Tomblin

7
“유해한 것으로 간주되는 Perl 프로토 타입” 기사를 읽어 보시기 바랍니다 .
tchrist

답변:


121

프로토 타입은 올바르게 사용하면 나쁘지 않습니다. 어려움은 Perl의 프로토 타입이 사람들이 종종 기대하는 방식으로 작동하지 않는다는 것입니다. 다른 프로그래밍 언어에 대한 배경 지식이있는 사람들은 프로토 타입이 함수 호출이 올바른지 확인하는 메커니즘을 제공하기를 기대하는 경향이 있습니다. 즉, 올바른 수와 유형의 인수가 있는지 확인합니다. Perl의 프로토 타입은이 작업에 적합하지 않습니다. 그것은의 오용 나쁜. Perl의 프로토 타입은 매우 다른 목적을 가지고 있습니다.

프로토 타입을 사용하면 내장 함수처럼 작동하는 함수를 정의 할 수 있습니다.

  • 괄호는 선택 사항입니다.
  • 컨텍스트는 인수에 부과됩니다.

예를 들어 다음과 같은 함수를 정의 할 수 있습니다.

sub mypush(\@@) { ... }

그리고 그것을

mypush @array, 1, 2, 3;

\배열에 대한 참조를 가져 오기 위해 를 쓸 필요가 없습니다 .

간단히 말해서 프로토 타입을 사용하면 고유 한 구문 설탕을 만들 수 있습니다. 예를 들어 Moose 프레임 워크는이를 사용하여보다 일반적인 OO 구문을 에뮬레이트합니다.

이것은 매우 유용하지만 프로토 타입은 매우 제한적입니다.

  • 컴파일 타임에 표시되어야합니다.
  • 우회 할 수 있습니다.
  • 컨텍스트를 인수로 전파하면 예기치 않은 동작이 발생할 수 있습니다.
  • 엄격하게 규정 된 형식 이외의 다른 것을 사용하여 함수를 호출하기 어렵게 만들 수 있습니다.

모든 세부 사항은 perlsub의 프로토 타입 을 참조 하십시오.


2
저는이 질문에 대한 최고의 답변이라고 생각하기 때문에이 답변을 수락했습니다. 프로토 타입은 본질적으로 나쁘지 않고 사용하는 방법입니다.
Alnitak

2
반면에 Moose 프로토 타입은 / awesome / p3rl.org/MooseX::Declare p3rl.org/MooseX::Method::Signatures
Kent Fredric


그렇다면 그들은 잘못된 이름입니까?
피터 모텐슨

69

문제는 Perl의 함수 프로토 타입이 사람들이 생각하는대로하지 않는다는 것입니다. 그들의 목적은 Perl의 내장 함수처럼 구문 분석 될 함수를 작성할 수 있도록하는 것입니다.

우선 메서드 호출은 프로토 타입을 완전히 무시합니다. OO 프로그래밍을 수행하는 경우 메서드에 어떤 프로토 타입이 있는지는 중요하지 않습니다. (따라서 프로토 타입이 없어야합니다.)

둘째, 프로토 타입은 엄격하게 시행되지 않습니다. 로 서브 루틴을 호출 &function(...)하면 프로토 타입이 무시됩니다. 따라서 실제로 유형 안전을 제공하지 않습니다.

셋째, 원거리에서 으스스한 행동입니다. (특히 $기본 목록 컨텍스트 대신 해당 매개 변수가 스칼라 컨텍스트에서 평가되도록하는 프로토 타입입니다.)

특히 배열에서 매개 변수를 전달하기 어렵게 만듭니다. 예를 들면 :

my @array = qw(a b c);

foo(@array);
foo(@array[0..1]);
foo($array[0], $array[1], $array[2]);

sub foo ($;$$) { print "@_\n" }

foo(@array);
foo(@array[0..1]);
foo($array[0], $array[1], $array[2]);

인쇄물:

a b c
a b
a b c
3
b
a b c

3 개의 경고 main::foo() called too early to check prototype(경고가 활성화 된 경우) 와 함께 . 문제는 스칼라 컨텍스트에서 평가 된 배열 (또는 배열 슬라이스)이 배열의 길이를 반환한다는 것입니다.

내장 된 것처럼 작동하는 함수를 작성해야하는 경우 프로토 타입을 사용하십시오. 그렇지 않으면 프로토 타입을 사용하지 마십시오.

참고 : Perl 6은 완전히 개편되고 매우 유용한 프로토 타입이 될 것입니다. 이 답변은 Perl 5에만 적용됩니다.


그러나 호출자와 서브가 동일한 수의 인수를 사용하고 있다는 유용한 검사를 제공합니다. 그렇다면 무엇이 문제입니까?
Paul Tomblin

2
아니; 일반적인 합의는 Perl 함수 프로토 타입이 본질적으로 이점을 제공하지 않는다는 것입니다. 적어도 Perl 5에서는 신경 쓰지 않는 것이 좋습니다. Perl 6은 다른 (더 나은) 이야기 일 수 있습니다.
Jonathan Leffler


10
수정 : 배열 슬라이스는 목록을 반환 하므로 스칼라 컨텍스트의 배열 슬라이스는 목록의 마지막 요소를 반환합니다. 두 번째 foo()요소 조각의 마지막 요소이기 때문에 두 번째에서 마지막으로 인쇄 2를 호출 합니다. 로 변경 my @array = qw(foo bar baz)하면 차이를 볼 수 있습니다. (제외로, 이것이 제가 던져 버리는 데모 코드에서 0 또는 1 기반 숫자 시퀀스로 배열 / 목록을 초기화하지 않는 이유입니다. 컨텍스트에서 인덱스, 개수 및 요소 간의 혼란이 저를 두 번 이상 물었습니다. 바보 같지만 사실입니다.)
pilcrow

2
@pilcrow : a b c귀하의 요점을 더 명확하게하기 위해 사용하는 답변을 편집했습니다 .
Flimm 2014

30

위의 두 포스터에 동의합니다. 일반적으로 사용 $은 피해야합니다. 블록 인수 (사용시 원형에만 유용하다 &), globs와 ( *) 또는 기준 프로토 타입 ( \@, \$, \%, \*)


일반적으로, 아마도 두 가지 예외를 언급하고 싶습니다. 첫째, ($)프로토 타입은 유용 할 수있는 명명 된 단항 연산자를 생성합니다 (확실히 Perl이 유용하다고 생각합니다. 가끔 있습니다). 둘째, 내장 기능을 재정의 할 때 (가져 오기를 통해서든 CORE :: GLOBAL ::을 사용하든) 일반적으로 내장에있는 프로토 타입에를 포함하더라도 고수해야합니다. 그렇지 않으면 $프로그래머를 놀라게 할 수 있습니다. 짝수) 내장이 그렇지 않으면 스칼라 컨텍스트를 제공하는 목록 컨텍스트를 사용합니다.
The Sidhekin 2015 년

4

Perl 서브 루틴 프로토 타입을보고있는 일부 사람들은 그것이 의미하지 않는 것을 의미한다고 생각합니다.

sub some_sub ($$) { ... }

Perl에게 이는 파서가 두 개의 인수를 예상한다는 것을 의미합니다. 그것은 Perl이 내장 된 것처럼 동작하는 서브 루틴을 생성 할 수 있도록하는 방법입니다.이 모든 것은 후속 코드에서 무엇을 기대할 수 있는지 알고 있습니다. perlsub 에서 프로토 타입에 대해 읽을 수 있습니다.

문서를 읽지 않고 사람들은 프로토 타입이 런타임 인수 검사 또는 다른 언어에서 본 것과 유사한 것을 참조한다고 추측합니다. 사람들이 Perl에 대해 추측하는 대부분의 것과 마찬가지로, 그들은 잘못된 것으로 밝혀졌습니다.

그러나 Perl v5.20부터 Perl에는 사용자가 기대하는 것과 유사한 것을 제공하는 실험적인 기능이 있습니다. Perl의 서브 루틴 서명 은 런타임 인수 계수, 변수 할당 및 기본 설정을 수행합니다.

use v5.20;
use feature qw(signatures);
no warnings qw(experimental::signatures);

animals( 'Buster', 'Nikki', 'Godzilla' );

sub animals ($cat, $dog, $lizard = 'Default reptile') { 
    say "The cat is $cat";
    say "The dog is $dog";
    say "The lizard is $lizard";
    }

이것은 프로토 타입을 고려하고 있다면 아마도 원하는 기능입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.