Search Results for '루비'

4 POSTS

  1. 2007.02.18 Ruby 변수 생성
  2. 2006.12.25 Prototyped-based Programming 3
  3. 2006.12.12 I hate Ruby's special global variables 1
  4. 2006.09.20 Mixin 2

Ruby 변수 생성

Posted 2007. 2. 18. 01:02
루비에서 변수 생성에 대한 규칙을 잘못 알고 있었다.

[skyul@dev ~]$ irb
irb(main):001:0> a
NameError: undefined local variable or method `a' for main:Object
        from (irb):1
irb(main):002:0> a = 1 if false
=> nil
irb(main):003:0> a
=> nil
irb(main):004:0>

처음 irb를 동작시키면 a라는 변수(혹은 메쏘드)가 정의되어 있지 않으므로 undefiend local variable or method 'a'라는 에러 메시지를 출력한다. 다음으로 실행한 구문은 a = 1 if false이다. if false는 무조건 거짓이므로 a = 1은 절대로 실행되지 않는다. 문제는 다음 행이다. 직관적으로 판단하기에 a = 1이라는 대입(assignment)가 일어나지 않았으므로 a는 여전히 undefiend 일 것이라 생각했지만, 예상과는 달리 a = nil이다.  즉 루비는 a = 1이 대입이 일어나야만 a 변수를 생성해 주는 것이 아닌 것이다. 프로그램을 차례대로 읽으면서 조건에 상관없이 a가 변수로 사용되었음을 알았기 때문에 그 후로는 a를 정의해 준 것이다.

로컬 변수와 메쏘드를 구분하는 것도 마찬가지이다. 다음은 "Programming Ruby: The Ruby Language, Variable/Method Ambiguity"에서 따온 예제이다.

def a
  print "Function 'a' called\n"
  99
end

for i in 1..2
  if i == 2
    print "a=", a, "\n"
  else
    a = 1
    print "a=", a, "\n"
  end
end

결과

a=1
Function 'a' called
a=99


위 예제는 a가 함수로도 사용될 수 있고, 변수로도 사용될 수 있음을 보여준다. a = 1 구문을 지나고 나면 a가 변수임을 알고, 변수로 호출한다. i == 2인 경우 이미 a에 1라는 변수가 할당되어 있지만 앞쪽에 나와있기 때문에 a = 1이라는 대입이 있었음을 알지 못한다. 따라서 이 경우 a를 메쏘드로 가정하는 휴리스틱을 사용한다.

다음과 같이 i == 1 조건이 먼저 나오면 어떨까?

for i in 1..2
  if i == 1
    a = 1
    print "a=", a, "\n"
  else
    print "a=", a, "\n"
  end
end

이 경우 a = 1 대입은 i == 1인 조건에만 있지만, 이 조건이 else 구문보다 앞서 있기 때문에 둘 다 a를 변수로 인식하고 1을 출력할 것이다.

a=1
a=1

Prototyped-based Programming

Posted 2006. 12. 25. 20:02
우리가 객체지향 프로그래밍 언어(object-oriented programming language)라고 부르는 언어 패러다임은 크게 1) 클래스 기반과 2) 프로토타입 기반의 언어로 양분할 수 있습니다. 클래스 기반 객체지향언어는 C++, 스몰토크, 자바, 루비처럼 클래스를 통해 현실 세계를 모델링하고, 클래스에서 객체(인스턴스)를 찍어내서 프로그래밍하는 모델을 말합니다. 반대로 프로토타입 기반의 언어에는 자바스크립트(JavaScript)가 있는데, 별도의 클래스 없이 이미 존재하는 객체를 클론(clone)해서 프로그램을 작성하는 방법입니다.

프로토타입 기반 언어에 대한 일반적인 비판은 동적 타이핑 언어에 대한 비판과 닮아 있습니다. 정확성(correctness), 안전성(safety), 예측성(predictability), 효율성(efficiency) 등이 떨어진다는 것입니다. [위키피디아 참고] 클래스 기반 객체지향언어에서 클래스는 외부 세계를 모델링(modeling)하는 방법일 뿐만 아니라 프로그램의 정확성을 확인할 수 있는 타입(type)이기 때문입니다. 쉽게 풀어서, 루비의 Array 클래스가 sort라는 메쏘드를 가지고 있다는 사실 자체가 클래스 사용자와 클래스 사이의 계약이 되기 때문입니다. 반대로 프로토타입 기반 언어에서는 클래스가 없기 때문에 이런 계약 관계를 쉽게 알아보기 힘들게 됩니다.

빠른 프로토타이핑(prototyping)과 개발 속도를 위해서 정적 타입 시스템(static type system)이라는 안전망을 포기한 스크립트 언어가 대부분 클래스기반 객체지향언어라는 점은 약간 의아합니다. 상업적으로 유일하게 성공한 프로토타입 언어인 자바스크립트를 제외하면, 프로토타입 언어는 Self, Cecil, Io 등 연구용 언어가 대부분이기 때문입니다. 자바스크립트의 표준인 EcmaScript조차 클래스 기반 언어로 전환을 이야기하고 있다고 합니다.

저는 개인적으로 파이썬 루비 같은 범용적 스크립트 언어면서 프로토타입에 기반한 언어가 대두하지 않을까 하는 생각을 해보기도 합니다. 동적 타이핑(dynamic typing)이라고 하지만 실제로는 타입 시스템이 없는 것이나 마찬가지인 스크립트 언어에서 굳이 클래스 기반 언어를 고집할 이유가 없기 때문입니다. 물론 객체지향 모델링 방법이나 베스트 프랙티스 등이 모두 클래스 기반 언어를 중심으로 논의되어 왔고, 기존 개발자들이 프로토타입 기반 객체지향 언어에 익숙하지 않다는 문제점이 있기는 합니다. 하지만 현재의 스크립트스러움을 극단으로 몰고 가려면 클래스 보다는 오히려 프로토타입이 아닐까요?

I hate Ruby's special global variables

Posted 2006. 12. 12. 01:12
I think the reason why Ruby is not so readable is because Ruby has special variables like $$.

$! latest error message
$@ location of error
$_ string last read by gets
$. line number last read by interpreter
$& string last matched by regexp
$~ the last regexp match, as an array of subexpressions
$n the nth subexpression in the last match (same as $~[n])
$= case-insensitivity flag
$/ input record separator
$\ output record separator
$0 the name of the ruby script file
$* the command line arguments
$$ interpreter's process ID
$? exit status of last executed child process

Ruby programmers who often use these awkward looking special variables may feel comfortable, but I hate that I have to memory the difference between $! and $@. What is the rule to memorize the meanings of these variables? Even worse, some variables names are confusing. For example, Ruby naming convention states that variables starting with $ are global variables, but $_ and $~ are closer to local variables.

Ruby emphasizes the principles of least surprise, but special variables really surprised me. [For those of you who are not familar with the principles of least surprise: Read"Applying the Rule of Least Surprise"  in The Art of Unix Programming written by Eric  Raymond.]

Ruby is a pure objected-oriented language and special variables do not fit well in OO concepts. Why don't we make a Process clsss and define pid and args methods to retrieve process ID and command line arguments instead of ugly $$ and $* variables?

Mixin

Posted 2006. 9. 20. 03:42
믹스인(mixin)은 일반적으로 스크립트 언어에서 다중 상속을 대신하는 방법으로 자주 쓰인다. 일반적으로 다중 상속을 사용하는 이유가 코드를 상속받기 위해서인데, Mixin은 클래스 계층을 변경하지 않고 코드만 포함시키는 방법을 제공하기 때문이다. 믹스인을 제공하는 대표적인 스크립트 언어가 루비인데, 다음 루비 프로그램을 살펴보자.


module Debug

  def whoAmI?

    "#{self.type.name} (\##{self.id}): #{self.to_s}"

  end

end

class Phonograph

  include Debug

  # ...

end

class EightTrack

  include Debug

  # ...

end

ph = Phonograph.new("West End Blues")

et = EightTrack.new("Surrealistic Pillow")

ph.whoAmI?       »       "Phonograph (#537766170): West End Blues"

et.whoAmI?       »       "EightTrack (#537765860): Surrealistic Pillow"

[http://www.rubycentral.com/book/tut_modules.html에서 발췌]


위에서 Phonograph와 EightTrack라는 두 가지 클래스를 정의했는데, 각각은 Debug 모듈을 임포트하고 있다. 루비언어는 클래스 내에서 모듈을 임포트할 경우 모듈 내의 함수가 자동으로 클래스의 메쏘드로 변환된다. 따라서 includeDebug라고 써주는 것만으로 두 클래스는 ph.whoAmI라는 메쏘드가 정의되게 된다. 즉 클래스 계층을 변화시키지 않고 코드만 재활용할 수 있는 것이다.