use base 와 use parent의 차이점

| | Comments (2) | TrackBacks (0)
hanekomu씨의 Use parent.pm instead of base.pm 이란 블로그 포스팅을 보고 다시 정리해볼 필요가 있어보여서 남김. Thanks hanekomu~

선행지식: 새로운 Perl OOP로 개과천선하기

Perl에서 OOP를 구현할 때 부모클래스 Game을 GoStop이라는 자식클래스가 상속할때 전통적인 방법은 다음과 같았다.

[Game.pm]
package Game;

sub new { ... }
...
1;

[GoStop.pm]
package GoStop;
BEGIN {
    require Game;
    our @ISA = 'Game';
}
...
1;

컴파일 타임에 적용되도록 하기 위해 BEGIN이라는 블럭안에 require로 Game모듈을 읽어들이고 부모클래스 리스트를 가지는 @ISA배열에 부모클래스를 명시하는 것이다.

하지만 이것은 왠지 ugly하고 말이 많아 보인다는 단점이 있다. 그래서 등장한 것이 base 라는 모듈이다.

[GoStop.pm]
package GoStop;
use base 'Game';
...
1;

깔끔하게 1줄로 줄었다. base는 많은 말을 간단하게 하나로 줄인 것 뿐만아니라 몇가지 추가적인 기능을 수행할 수 있게 만들어 졌다. 만약에 Game패키지(클래스)가 별도의 파일이아닌 GoStop패키지와 같은 파일에 있다면

package Game;

sub new { ... }
...

package GoStop;
our @ISA = 'Game';
...
1;

이미 Game이란 패키지가 GoStop 패키지가 만들어질 때 같은 파일안에서 로딩된 상태이므로 위처럼 따로 require과정은 필요하지 않게 되는데, 이 경우에 다음과 같이 base를 써서

package Game;

sub new { ... }
...

package GoStop;
use base 'Game';
...
1;

이런식으로 하면 base는 Game.pm 파일이 있으면 우선적으로 그것을 로딩해서 사용하지만( 이 경우는 없다고 가정) 없을때도 같은 파일내에서 이미 로딩된 패키지(클래스)가 있다면 에러가 나지 않고 알아서 그것을 부모로 사용하므로 our @ISA = 'Game'과 같은 효과를 발휘 할 수 있다.

그 이외에도 base에는 Perl OOP구현의 초창기 시절 실험적으로 시도되었던 pseudo hash/restricted hash를 이용한 fields모듈의 클래스필드 구현/상속 및 모듈간에 VERSION정보 처리등이 들어있지만 이제는 outdated된 테크닉이라  이런 불필요한 부분을 제거하고 슬림하게 다시 태어난 것이 바로 parent 이다.( parent 모듈은 Perl 5.10.0 버젼 부터 Perl배포본에 기본적으로 포함되어 나오는 Perl core모듈로 들어갔으며 대표적인 Perl 웹프레임웍인 Catalyst도 이제 base대신 parent를 사용한다. )

GoStop.pm 을 parent로 다시 쓰면

[GoStop.pm]
package GoStop;
use parent 'Game';
...
1;

로 쓸 수 있으며 base의 경우 무조건 지정하는 부모클래스 패키지가 별도의 파일로 존재하면 그것을 우선시 하고 별도의 모듈 파일없이 부모클래스가 같은 파일내에 있으면 같은 파일내의 것을 부모로 삼는 반면 parent는 이런 경우에 -norequire 옵션으로 어떤 식으로 동작할 것인지 조정이 가능하다.

만약 한 파일 내에서 다음과 같이 쓰면

package Game;

sub new { ... }
...

package GoStop;
use parent 'Game';
...
1;

parent는 같은 파일내 Game을 부모로 삼지 않고 별도의 Game.pm 파일을 내부적으로 require로 읽어들여서 부모로 삼는다. ( Game.pm 파일이 있다면 base도 똑같이 동작할 것이다.) 반면 -norequire 옵션을 써서

package Game;

sub new { ... }
...

package GoStop;
use parent -norequire, 'Game';
...
1;

처럼 하면 Game.pm 파일을 require하지 않고 같은 파일내의 Game을 부모로 삼게 된다.( Game.pm 파일이 존재한다면 base의 경우 이런식의 동작은 할 수 없다. )

그리고 parent 모듈 문서에 보면

package MyHash;
use Tie::Hash;
use parent -norequire, 'Tie::StdHash';

과 같은 예제 코드가 있는데 Tie::Hash 라는 모듈파일을 보면 내부적으로 Tie::StdHash라는 패키지(클래스)를 같이 포함하고 있다. 이경우는 use Tie::Hash; 로 이미 Tie::StdHash 패키지도 같이 로딩된 상태이므로 -norequire 옵션으로 별도의 모듈 파일을 읽어들이지 않고 이미 읽어들인 Tie::Hash 모듈내의 Tie::StdHash를 부모로 삼겠다는 의미이다.

최신 Perl OOP 프레임웍인 Moose 에서는 부모클래스를 상속할 때 extends라는 sugar함수를 사용하지만 Moose를 사용하지 않는 Perl OOP 구현에서는 parent를 사용하는 방식이 가장 최신의 방식임을 알아두도록 하자.