arraysizeof macro

Date: 12 Oct 2009 Comments: 2 so far

다음 macro는 array의 length를 구하는 것인데 해석이 되시나요?

template <typename T, size_t N>
char (&Helper(T (&array)[N]))[N];
#define arraysize(array) (sizeof(Helper(array)))

...

안되신 분들을 위한 설명입니다. ;)

위 코드는 다음 두가지 사실만 알고 있다면 (비교적) 쉽게 이해됩니다.

sizeof는 function call syntax에 대해서도 동작하며 그 function의 return type에 대해 동작한다.

int foo() { return int(); }
...
sizeof(foo()) == sizeof(int)

array type의 reference를 리턴하는 method의 signature는 다음과 같다.

char (&bar)[10]() { ... }

이를 바탕으로 arraysizeof를 만들려면 char(&)[N]을 리턴하는 method를 만들면 되죠. 여기서 N은 array의 length.

template <typename T, size_t N>
char (&Helper(T (&array)[N]))[N] {
...
}

위 함수는 T(&)[N]을 parameter로 받아 char(&)[N]을 리턴합니다. 물론 T(&)[N] parameter는 이 template method의 implicit instantiation이 동작하도록 하기 위해 필요합니다. 마지막으로 sizeof는 method body가 필요없으므로...

template <typename T, size_t N>
char (&Helper(T (&array)[N]))[N];

끝.

참고로 이런 코드가 필요한 이유는 널리 쓰이는 "sizeof(array) / sizeof(*array)" macro가 다음과 같은 경우 compile error없이 오동작하기 때문입니다.

void foo(int array[]) {
  int size = sizeof(array);
}

이 코드에서 array는 pointer와 같이 취급되어 sizeof(array)는 sizeof(int*)가 됩니다.

Tags: ,

Java generic in return context

Date: 25 Sep 2009 Comments: 7 so far

아래 코드를 보시고 1, 2번 라인중에 어디서 에러가 날 지를 찾아보세요.

interface B {
  void doB();
}
class D implements B {
  public void doB() {}
}
interface H {
  B getB();
}
class HImpl implements H {
  public B getB() {
    return new D();  // 1)
  }
}
...
H h = new HImpl();
D d = h.getB(); // 2)

네, 2번 라인입니다.

그럼 다음 코드는?

interface B1 {
  void doB1();
}
interface B2 {
  void doB2();
}
class D implements B1, B2 {
  public void doB1() {}
  public void doB2() {}
}
interface H {
  <T extends B1 & B2> T getB();
}
class HImpl implements H {
  public <T extends B1 & B2> T getB() {
    return new D();  // 1)
  }
}
...
H h = new HImpl();
D d = h.getB(); // 2)

네, 1번입니다. 잘 이해가 되질 않아 사내 메일링 리스트에 물어보니

I think you're seeing and interpreting it as "this method can return anything that implements both interfaces". What it's actually saying is "the caller is going to tell you a specific class that implements both interfaces, and you must return one of those".

이랍니다. 즉 T 타입이 아직 결정되지 않은 상태라 D와 T는 compatible한 타입이 아닌거죠.

강제로 casting을 해서 컴파일이 되게 만들면 그 코드는 runtime error (ClassCastException)를 발생하게 됩니다. 다음 코드를 보세요. 즉 이런 방법으론 도저히 type-safe한 코드를 작성할 수 없습니다.

class D2 implements B1, B2 {
  public void doB1() {}
  public void doB2() {}
}
...
D2 d = h.getB(); // ClassCastException!!

이 같은 상황을 방지하기 위해 1번 라인에서 에러를 내 주는 것이죠.

코딩 가이드라인을 만들어 보자면 "method의 parameter로 사용되지 않는 type variable을 사용하면 안된다"입니다. 다음과 같은 경우는 parameter로도 사용되고 있으므로 문제가  없는 경우들입니다.

<T> T makeInstance(Class<T> cls) { return cls.newInstance(); }
...
<T extends Comparable<? super T>> T min(T a, T b) {
 return a.compareTo(b) < 1 ? a : b;
}

위의 예제 코드같은 경우 아래와 같은 방법으로 type-safe하게 작성될 수 있습니다.

interface B1 {
  void doB1();
}
interface B2 {
  void doB2();
}
class D implements B1, B2 {
  public void doB1() {}
  public void doB2() {}
}
interface H  <T extends B1, B2> {
  T getB();
}
class HImpl implements H<D> {
  public D getB() {
    return new D();  // 1)
  }
}
...
H<D> h = new HImpl();
D d = h.getB(); // 2)

사실... 아직도 잘 모르겠어요. Java generic. =(

Tags: ,

Access level of methods in package-private class

Date: 22 Sep 2009 Comments: 2 so far

Java에서 (C++도 마찬가지지만) 권장되는 access level 사용법은 다음과 같습니다.

Use the most restrictive access level that makes sense for a particular member.

쉽게 얘기해서 private으로 충분하면 private을 쓰고 다음으로 package-private, protected, public 순으로 쓰라는 얘기.

그런데 C++와는 달리 Java는 class에도 public과 package-private 두 종류의 access level이 있습니다. 이 중 public class의 method들은 위의 권장 사항을 따르면 될 듯 한데 package-private class일 경우는 어떨까요?

Package-private class에서는 실제 사용될 수 있는 조건으로 봤을 때 method들이 public이건 protected건 모두 package-private과 같은 조건을 가집니다. 즉, 아무리 method의 access level을 public이나 protected로 해봐야 다른 package에선 이 method를 사용할 수가 없습니다. 따라서 the most restrictive한 level을 사용하라는 위 권장 사항을 따르자면 package-private class의 method들은private이 아니라면 모두 package-private access level을 사용해야 합니다.

그런데 코딩을 하다보니 이 방법엔 한가지 문제가 있더군요. 가끔 package-private class를 public class로 만들어야 할 경우들이 생기는데 이때 method들이 모두 package-private이면 다른 package에서 사용할 수가 없습니다. 그래서 다시 method들의 access level을 조정해야 할 필요가 생기는데 이 시점은 이미 코드를 작성했을 때와 멀어서 자칫 잘못된 access level을 지정할 수 있게 됩니다.

그래서 생각한건데... package-private class의 method들을 만들 때 access level은 이 class의 access level을 public으로 가정하고 작성하는 것이 어떨까요?

Valuing Ambiguity

Date: 17 Sep 2009 Comments:0

A History of CLU

Date: 16 Sep 2009 Comments: 2 so far

Checked exception 관련 글들을 찾아 보다가 읽게 된 문서입니다. CLU라는 프로그래밍 언어를 개발하게 된 배경과 과정에 대한 내용인데 정말 재밌네요. 참고로 문서가 좀 길어보이지만 한 1/3은 부록입니다. :)

A History of CLU

거의 30~40년전 이야기인데 현재 사용하고 있는 언어들이 여기서 앞으로 많이 나간것 같아 보이지 않네요.

As mentioned, the concept of data abstraction arose out of work on structured programming and modularity that was aimed at a new way of organizing programs. The resulting programming methodology is object-oriented.

A keystone of the methodology is its focus on independence of modules.

Achieving independence requires two things: encapsulation and specification.

Specifications are needed to describe what the module is supposed to do in an implementation-independent way so that many different implementations are allowed. (Code is not a satisfactory description since it doesn’t distinguish what is required from ways of achieving it. One of the striking aspects of much of the work on object-oriented programming has been its lack of understanding of the importance of specifications; instead the code is taken as the definition of behavior.)

Specifications also allow code that uses the abstraction to be written before code that implements the abstraction, and therefore are necessary if you want to do top-down implementation.

In essence, having a language enforce encapsulation means that the compiler proves a global property of a program; given this proof, the rest of the reasoning can be localized.

CLU favors program readability and understandability over ease of writing, since we believed that these were more important for our intended users.

We worked on the implementation in parallel with the design. We did not allow the implementation to define the language, however.

이 글을 읽고나니 Kent Beck이 세미나에서 언급했던 Structured Design이라는 책이 읽고 싶어지네요. Kent Beck도 이 책을 언급하며 수십년전에 쓰여진 책인데 필요한 내용이 전부 있다... 뭐 이렇게 소개했었던 것 같은데...

Tags: