10월, 2014의 게시물 표시

[Scala] 함수 선언과 호출에서의 괄호 생략

위에서 보듯이 Scala에서는 인자가 0개인 함수를 선언하거나 호출할 때 괄호를 생략할 수 있다.1) 컴파일 타임에 괄호 생략에 대해 아무런 제약도 하지 않고, 컴파일된 byte code에도 차이가 없다. 그렇다고 아무 괄호나 생략해도 되는 것은 아니다. 언어적으로는 괄호 생략에 관해 아무 제약을 하지 않지만, side-effect가 없을 때만 괄호를 생략하여야 한다.2)

 side-effect가 없는 함수에 대해서만 괄호를 생략하는 것은 함수가 선언된 모양만으로 그 함수가 하는 일을 추측할 수 있기 때문에 코드의 가독성을 높이는 데 도움이 된다. 그렇다면 어째서 컴파일 타임에 side-effect가 없는 함수에 대해서만 괄호를 생략할 수 있도록 강제하지 않을까?
 이유는 간단하다. 컴파일러가 함수가 side-effect가 있는지 없는지 구분할 수 없기 때문이다. Haskelmonad같은 개념을 도입하여 side-effect를 분리해 낼 수 있을지도 모르지만, Scala는 그런 개념을 도입하지 않고, 사용자에게 책임을 넘겼다.

 side-effect는 functional 프로그래밍에서 매우 중요한 부분이기 때문에 이것에 대한 책임을 프로그래머에게 넘겼다는 점에서, Scala의 안 좋은 부분이라고 평하는 사람도 있다. 하지만 나는 이 정도 자유는 프로그래머에게 넘기는 것이 적당하다고 생각한다.

 예를 들어, 무언가 side-effect가 없는 일을 하는 함수가 있을 때 그 함수가 호출되면 logging을 하도록 수정하였다고 생각해보자. 이 함수는 side-effect가 있는 함수라고 봐야 할까? side-effect가 없는 함수라고 봐야 할까? 엄밀한 의미에서 따져본다면 side-effect가 있는 함수라고 분류해야겠지만, 실제 돌아가는 logic을 생각해보면 이 함수를 side-effect가 있다고 구분하는 것은 뭔가 억울(?)하다.
1)http://docs.scala-lang.org/style/method-invocation.html#arity-0
2)

Big endian과 little endian

이미지
Endianness는 것은 메모리상에서 byte를 배치하는 방법을 말한다. 크게는 big-endian과 little-endian으로 구분된다.

Big endian 우선 big-endian은 가장 큰 byte(most significant byte, a.k.a. MSB)가 가장 앞에 나오는 방식이다. 일반적으로 사람이 사용하는 방식이라고 생각하면 된다.
 Big-endian은 사람이 흔하게 사용하는 방식이기 때문에 big-endian으로 기록되어 있는 값은 사람이 읽기 쉽고, bit order와 byte order, word order까지 일관성 있다.

Little endian Little-endian은 가장 작은 byte(least significant byte, a.k.a. LSB)가 가장 앞에 나오는 방식을 의미한다. 다시 말해 위의 그림처럼 0x0A0B0C0D를 메모리에 올리고, 메모리를 순서대로 읽으면 0x0D0C0B0A가 나온다는 것이다.
 처음 little-endian을 보면 이게 도대체 뭐하는 짓인가 싶은데 현대의 컴퓨터들은 대부분 little-endian을 이용한다. 왜냐하면 인텔이 머신을 이렇게 만들었으니까. 그렇다면 인텔은 왜 little-endian을 사용할까?

 Little-endian이 컴퓨터에서 컴퓨터의 연산을 아주 미묘하게 빠르게 만들어준다. little-endian을 사용하면 아무런 연산 없이 사이즈가 다른 변수로 casting 할 수 있다. 또한, 덧셈할 때도 little-endian을 사용하는 게 chip을 설계하기 쉽다. 언제나 LSB의 offset이 0으로 같아서 몇 바이트 변수를 더하더라도 언제나 offset이 0인 byte부터 시작하여 더하여 올릴 수 있기 때문에 쉽게 가산기를 구현할 수 있다.

 근데 이게 사람이 메모리를 읽기 어렵게 만들면서까지 성능을 올릴 필요가 있는지는 모르겠다. 개인적인 생각으로는 이렇게까지 해서 성능을 올리고 칩을 간단하게 만들 필요가 있을지 잘 모르겠다. 하지만 인텔이 little-endian…

[C#] extension method - 존재하는 class 확장하기.

지난 글에서 이미 존재하는 class에 새로운 함수를 추가해주는 Scala의 implicit class라는 기능을 소개했다. Scala의 implicit class는 라이브러리에서 제공해주어 내가 수정할 수 없는 class를 확장할 때 유용하게 사용되며, 코드의 일관성을 유지하기 위해 원래 class에는 최소한의 기능만을 구현하고, 추가적인 구현은 종류별로 여러 implicit class를 구현하는 방식으로 사용되기도 한다. class의 선언과 구현 detail을 분리할 수 있게 해주는 여러모로 재밌는 기능이다.

 C#은 이런 기능을 extension method라는 방식으로 구현하였다.
 Extension method가 없던 시절(사실 없던 시절은 꽤 오래전 이야기다. Extension method가 유명하지 않아서 그렇지 vs2008부터 들어갔던 기능이다.)에는 확장하고 싶은 class를 상속받아 새로운 class를 만들거나, wrapper class를 만들거나, static method를 만들어 객체를 넘기는 방식으로 구현하여야 했다.
 하지만 이런 방식들은 전부 문제가 있다. 우선 상속으로 새로운 class를 구현하는 방법은 확장할 클래스가 sealed class일 경우 사용하지 못한다. wrapper class를 만드는 방법은 새로 만드는 함수 이외에 다른 함수들을 wrapper class로 연결해 주어야 해서 코드가 매우 boilerplate 해진다. 무엇보다 이 두 방법은 모두 하고자 하는 일에 비해 너무 많은 코드를 작성해야 한다. 마지막 static method를 만드는 방법은 함수를 호출하는 모양이 달라서 코드의 일관성이 없어진다.
 하지만 extension method를 사용하면 이런 문제를 쉽게 해결할 수 있다.

 Extension method를 정의하는 것은 간단하다. 확장하고자 하는 method를 static class의 static method로 정의하면서 첫 번째 인자에 this modifier를 붙이면 된다.
 전체적으로 작업할…