ruby-dev 소식: 클래스 로컬 인스턴스 변수표기법

Posted by 미스란디르 Thu, 15 Feb 2007 16:23:00 GMT

얼마전에 사사다 코이치씨가 1.9(trunk) 에서 singleton.rb를 사용할 경우 에러가 난다는 포스팅을 했었다. ruby-dev:30263

요녀석은 make test-all을 하면 볼 수 있고, 저 포스팅의 예제코드를 돌려봐도 마찬가지로 볼 수 있다. (현재시각의 trunk에는 workaround처리가 되어 있음)

이 에러는 r11630 에서 발생한다. 무엇인고 하면, @가 인스턴스 변수, @@가 클래스 변수인데, @_이 클래스 로컬 인스턴스 변수를 뜻하는 prefix가 되면서 부터다.

어떻게 동작하는 것일까? ruby-talk:86984 를 에서 소개한 코드를 보자.

class A
  def m
    @var  = "hi"      # regular instance variable
    @_var = "hello"  # class-local instance variable
  end
end

class B < A
  def n
    puts @var.inspect             # same as @var, above
    puts @_var.inspect            # not same as @_var above
  end
end

o = B.new
o.m
o.n

이 코드의 예상 결과는? 주석을 참조한다면 어떻게 될지 짐작이 간다. 결과는 다음과 같다

"hi" 
nil

내부적으로 어떻게 동작할까? 당신이라면? 나는 코드를 미리 봐버려서 짐작할 기회가 없었다. 답은 심볼 이름뒤에다 클래스를 붙여버린 것이다. 예를들자면 위의 예에서는 @_var라면 :_var/A가 된다. 이러면 B의 객체의 scope에서는 @_var를 접근할 때 :_var/B 를 찾게 되지만, 이녀석은 당연히 없으니 @_var는 값이 들어간적이 없는 인스턴스 변수, 즉 nil이 된다.

다시 처음의 문제제기로 돌아와서. ivar2(클래스 로컬 인스턴스 변수)를 구현하는데 사용한것이 @다음의 ’_’ 다. 그리고 Singleton의 경우, 인스턴스 변수로 @__mutex__를 사용해서 싱클튼을 구현하고 있다. (동시 접근을 막기 위해). 일단 싱글튼 코드를 먼저 살펴보자.

  class << Singleton
    def __init__(klass)
      klass.instance_eval {
        @__instance__ = nil
        @__mutex__ = Mutex.new
      }   
      def klass.instance
        return @__instance__ if @__instance__
        @__mutex__.synchronize {
          return @__instance__ if @__instance__
          @__instance__ = new()
        }
        @__instance__
      end 
      klass
    end
    def inclued(klass)
      Singleton.__init__(klass)
    end
  end

사실은 included에 코드가 몇줄 더 있지만 귀찮으니까 뺐다. included는 모듈이 클래스에 믹스인 될때 호출되는 메서드(말하자면 콜백)이다. 그리고 형식인수로 그 포함한 클래스를 받는다. 그리고 그것을 Singleton.init으로 넘기고, instance_eval을 사용해서 그 클래스의 scope에서 @mutex 를 초기화한다. 그리고 겸사겸사 klass.instance 메서드(이건 말하자면 클래스 메서드) 도 정의하는데, 이때 지금 초기화한 @mutex 를 사용한다.

뭐 보기만 해서는 전혀 문제가 없어보인다.

여기서 잠깐 다른 코드를 보고 넘어가자.


class Merong
  def m
    @__y__ = "Yes!" 
  end
  attr_accessor :__x__
end

m = Merong.new
m.m
m.instance_eval { @__x__ = "Yes!" }
puts m.instance_variables.inspect

위에서 말한대로라면, @x__/Merong @y__/Merong 이 보여야 한다. 그러나!
[:@__x__/#<Class:#<Merong:0xb7ec4390>>, :@__y__/Merong]

문제는 요것. instance_eval을 사용할 경우 좀 애매하게 다른 결과가 나온다.

따라서 Singleton의 경우도 그럴거라고 예상할 수 있다. 귀찮아서 실제로 보는건 생략.

현재는 이것과 관련해서 _ 를 계속 쓸 것인지, 아니면 (v) 라던가 기타 다른 형식을 쓸 것인지를 고민하고 있다. (마츠씨와 사사다씨가) ================ 사실 이 포스팅을 쓰면서, @__mutex__ 에 대입하는 부분과 사용하는 부분이 scope가 다르기 때문일꺼라고 막연하게 짐작했는데, 예상치 못한 결과가 나왔다. 아마도 ivar2관련 버그이리라.

Posted in  | Tags , , ,  | no comments | no trackbacks

Comments

Trackbacks

Use the following link to trackback from your own site:
http://tisphie.net/typo/trackbacks?article_id=ruby-dev-%EC%86%8C%EC%8B%9D-%ED%81%B4%EB%9E%98%EC%8A%A4-%EB%A1%9C%EC%BB%AC-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4-%EB%B3%80%EC%88%98%ED%91%9C%EA%B8%B0%EB%B2%95&day=16&month=02&year=2007

Comments are disabled