라는 글을 보고 Perl에서는 어떤지 한번 정리해 봅니다. 우선 윗글에 있는 코드를 Perl식으로 바꾸면 아래와 같습니다.
#!/usr/bin/env perl sub a { print 'a'; } sub b { print 'b'; } sub f { my ($arg1, $arg2) = @_; $arg1; } f(a,b);
Perl에서는 Ruby,Python과 달리 변수에는 sigil이라고 하는 $를 앞에 붙여서 변수를 만듭니다. 따라서 변수명과 함수명이 같아도 엄연히 다른것이며 충돌하거나 암묵적으로 호출될 일은 없습니다.
위의 f함수에서처럼 인자로 그냥 bareword를(여기서는 a b) 사용했을경우 선언된 함수이름이 존재하면 함수를 호출하게 됩니다. 따라서 f(a,b)는 a함수, b함수 가 호출된 결과가 들어가게 됩니다. 각 함수가 차례로 호출되면서 ab가 차례로 찍히고 Perl은 { }블록형태의 함수에서 return문으로 명시적으로 리턴하지 않으면 블록내에서 마지막으로 평가된 값이 리턴됩니다. 여기서는 print 문이 성공하면 참(1)값을 돌려주기 때문에 각 함수의 마지막 평가값은 1이 되어서 결과적으로는 f(1,1)이 호출되고 f함수에서 마지막 평가값인 $arg1의 값은 1이 되어 f함수의 리턴값은 1이 됩니다. 마츠가 루비를 만들때 Perl을 많이 참고로 해서 그런지는 모르겠지만 여기 까지는 Ruby와 비슷하게 동작하는 것 같네요.
그럼 Python과 같이 함수의 참조가 넘어가서 f함수 내부에서 넘겨받은 함수 참조를 통해 호출하려면 Perl에서는 어떻게 해야 할까요?
#!/usr/bin/env perl my $a = sub { print 'a'; }; sub b { print 'b'; } my $b = \&main::b; # 같은 패키지 내부면 my $b = \&b; 로 해도 됨 sub f { my ($arg1, $arg2) = @_; $arg1->(); &$arg2; } f($a,$b);
Perl에서 함수레퍼런스는 함수가 호출되는 메모리상의 주소값을 가진 스칼라 변수 입니다. $같은 sigil이 없는 Python이나 Ruby에서는 동일한 이름을 가진 변수와 함수의 식별자(identifier)가 때로는 값 혹은 호출로 때로는 값 혹은 참조로 암묵적으로 동작하게 되지만 Perl에서는 확실히 구별됩니다. 위 Perl코드의 $a는 익명함수의 주소값을 $a라는 변수에 넣은것이고 $b는 이미 Perl의 기본 네임스페이스인 main패키지에 선언되어 심볼테이블에 기록된 b함수의 주소값을 $b변수에 넣은것입니다. 이제 두가지 방법으로 스칼라변수 $a, $b에 저장된 함수레퍼런스를 f함수에 넣어 호출하게 되면 f함수 내부에서 넘겨받은 함수 레퍼런스를 통해 함수를 호출 할때는 $arg1->() 처럼 뒤에 ->()를 붙여서 호출할 수도 있고 &$arg2 처럼 앞에 &를 붙여서도 호출 가능합니다. Perl이 레퍼런스를 다루고 호출하는 문법을 보면 C나 Javascript 와 유사한 느낌적인 느낌이 들지 않나요?
Perl의 sigil이 코드를 noisy하게 보인다고 까는 사람도 있지만 저는 코드의 앞뒤를 뒤져보지 않아도 바로 이 코드의 의도를 명확하게 구별하고 알려주는 효자 같은 존재라고 봅니다.
PS: Perl 문법이 더 궁금한 분은 https://github.com/aero/perl_docs 을 참고하세요~
Java로 하면 아래 같은 느낌 일려나요;;;
답글삭제https://gist.github.com/anonymous/5f7c4b63707540a030e0
(A만 출력 합니다.)
sigil을 통한 명시적인 호출이 어떻게 보면 복잡해 보이지만 또 어떻게 보면 심플해 보여서 신기방기 하네요 ㅋㅋㅋㅋㅋㅋ
-TAFKA_HoliK
Perl에서 use strict; 모드를 쓰지 않을 경우 다음 처럼 함수 이름을 넘겨 심볼릭레퍼런스( http://ko.perlmaven.com/symbolic-reference-in-perl )를 통해 호출도 가능합니다.
답글삭제#!/usr/bin/env perl
sub a {
print 'a';
}
sub f {
my ($arg) = @_;
$arg->();
}
f('a');
하지만 현대적 Perl에서는 use strict;를 항상쓰기를 추천하고 심볼릭레퍼런스는 아주 특수한 경우 말고는 쓸일이 없죠.