Dynamic Scoping in Perl

By | 2009/09/29

  올해 1학기 컴파일러 수업 시간에 Dynamic Scoping에 대해서 간단히 얘기를 들었습니다. Compile time에 결정되지 않는다는 것에 ‘그럼 프로그래머는 머리 속에 실행 과정을 생각하면서 만들어야겠구나. 참으로 어렵겠네.’라는 생각을 하였습니다. 물론 그렇지 않은 프로그래머는 없겠지만 stack까지 고려해야 하는 것인가 싶었습니다.

  그래서 이런 생각을 하였습니다.

Dynamic Scoping을 쓰는 언어를 쓰는 사람은 누구일까?

  그렇게 복잡해 보이는 언어를 쓰는 사람이 누구인지 궁금하였습니다. 과연 어느 세계에 사는 사람일까도 궁금하였습니다.

  하지만 알고 보니 제가 바로 그 상상하던 사람이었습니다.

c4

  이번 프로그래밍 언어론 수업 자료입니다. Dynamic scoping을 사용하는 언어로 Perl을 얘기하고 있습니다.

  이글루스 –> Textcube를 Perl로 만든 경험이 있듯이 휴학할 때 Perl을 배우고 지금까지 종종 필요할 때마다 사용하였습니다. 그런데 그 언어가 Dynamic Scoping을 쓰다니…

  그래서 확인을 위해 ppt slide에 예제라고 나와있는 것을 해보았습니다.

c7

  위와 같은 코드에서 Static scoping이라면 1이 Dynamic scoping이라면 2가 출력되어야 합니다. Static이라면 first 함수에서 n을 1이라고 할당하였기 때문이고, Dynamic이라면 first에서 건드리는 n은 second 함수에서 생성한 n이기 때문입니다. 즉, second 함수 내의 integer variable n을 1로 할당합니다. 따라서 second 함수가 호출되기 전에 n을 2로 할당하고 이것이 변하지 않기에 2를 출력합니다.

  이를 Perl에서 실험해보았습니다.

c8

  1: #!/usr/bin/perl
  2: 
  3: $n = 0;
  4: 
  5: print "1. n : " . $n . "\n";
  6: 
  7: sub main
  8: {
  9:     sub first
 10:     {
 11: 		$n = 1;
 12:     }
 13: 	sub second
 14: 	{
 15: 		local $n;
 16: 		first();
 17: 	}
 18: 	
 19: 	$n = 2;
 20: 	second();
 21: 	print "2. n : " . $n . "\n";
 22: }
 23: 
 24: main();
 25: 

  Perl에서는 확실히 2가 나오는 것을 확인하였습니다. Perl은 Dynamic Scoping이네요.^^;;

  그럼 왜 Perl에서 Dynamic Scoping을 사용하는 것일까요? 아직 명확하게 배우지 못해 잘 모르겠지만 이런 글을 발견하였습니다.

Lexical scoping generally needs declarations to work.

Just taking the first use of a variable may not be what the coder intends and Larry (in an Apocalpse, if I recall correctly) couldn’t find a good heuristic to intuit the intended lexical scope. So you’ll end up having to declare your lexicals even in Perl 6.

출처 : Why does Perl use dynamic scoping?

  historical 이유인가요?^^;;

  여하튼 그 때 상상하였던 사람이 바로 자신이었다는 것을 충격으로 받아들이며 이 글을 마칩니다.

 

참조

4 thoughts on “Dynamic Scoping in Perl

  1. keedi

    펄에서 local은 전역 변수를 지역화 하기 위해서 종종 사용합니다. 더 정확하게 말하면 펄에서는 전역변수라기 보다는 패키지 변수라고 하는 것이 맞을테구요. local로 패키지 변수(전역 변수)를 선언하는 순간 선언한 그 시점 이후의 모든 함수 호출에서 local로 선언한 값을 대체해서 사용하고 선언한 범위(scope)가 끝나는 순간 공부하신 것처럼 원래의 패키지 변수(전역 변수) 값으로 되돌아갑니다.

    보통은 쓸일이 별로 없는데 굳이 언제 쓰냐면 모듈 만들 때 패키지 변수를 다룰 때 쓰곤합니다. 패키지 변수는 전역 변수라서 my를 쓸 수 없으니까요. 하지만 그것보다 더 많이 쓰는 경우는 특수 변수를 localize하려고 할 때 쓰는 것 같습니다.

    예를 들면 다음과 같은 경우죠:

    my $eat_everything = do { local $/; };

    조금 더 풀어쓰면,

    my $eat_everything = do { local $/ = undef; $slurp = };

    인데요. 블럭의 마지막의 값이 마치 함수의 반환값처럼 표현식의 최종 값이 되기 때문에 $eat_everything에는 파일 전체의 내용이 들어갑니다.

    $/ 변수는 기본적으로 시스템에 맞게 개행 문자로 설정되어 있습니다. 펄에서 줄단위로 읽어들이는 readline 류의 연산 즉 $line = ; 라고하면 한 줄 씩 읽어들일 수 있는 이유가 $/ 변수의 값을 참조하기 때문입니다.

    그런데 이 $/ 변수는 시스템 전체에 영향을 미치기 때문에 이 값을 변경하는 것은 세심한 주의가 필요로 합니다. 적어도 백업을 하고 복구하는 작업이 필요하겠죠. 동적 범위를 지원하지 않는다면 아마 다음처럼 써야 했을 것입니다.

    my $old_line_breaker = $/;
    $/ = undef;
    my $eat_everything = ;
    $/ = $old_line_breaker;

    사실 한 번 쓰고 말 $old_line_breaker을 보이게 하는 것은 별로 좋은 일이 아니라고 생각한다면 아마 다음처럼 작성할 것입니다.

    my $eat_everything;
    {
    my $old_line_breaker = $/;
    $/ = undef;
    $eat_everything =
    $/ = $old_line_breaker;
    };

    사실 local이 이런 경우를 위해 만들어졌다고 할수는 없겠지만, 펄의 자유로운 문법과 동적 범위 개념이 합쳐지면 파일 하나를 통째로 메모리에 올리는 코드가 다음 처럼 간단해진답니다.

    #!/usr/bin/perl

    use strict;
    use warnings;

    open my $fh, ‘.bashrc’
    or die “cannot open bashrc: $!”;
    my $contents = do { local $/; < $fh> };
    close my $fh;

    print $contents;

    사실 상기 코드는 Perl Best Practices에서 관용구처럼 추천하는 기법이니 즐겨 쓰셔도 무방할 것으로 보입니다. :-)

    Reply
    1. NoSyu

      오.. Dynamic Scoping으로 간단한 코드를 만들 수 있는 것인가요?
      아직 100% 이해를 다 하지 못했습니다만, Dynamic Scoping이 사용되는 곳을 조금이나마 알 수 있었습니다.
      너무나 자세한 설명 고맙습니다.ㅜㅜ

      Reply
  2. keedi

    참 local 및 my 등등과 관련해서는 perlsub 페이지에 잘 설명되어 있습니다. perldoc perlsub 로 참고하시면 도움 많이 되실거에요. :-)

    Reply

Leave a Reply