View

300x250

이번에 코드를 두드리면서 예상치 못한 코드 에러를 만났다.

ㅤㅤ

void 반환형에 관련된 문제였는데, 대략적으로는 아래의 상황이다. 함수는 void 타입을 반환하는 함수가 하나 정의되어 있었다.

Either<Failure, void> foo() {
    if (조건에 따라) {
        return null;
    } else {
        return Failure(...);
    }
}

ㅤㅤ

그리고 나는 이 값을 받아 void 타입의 함수가 정상적으로 잘 종료되었는지 체크해보려 했다.

final result = foo();

if (result가 null) {     << 여기에서 문제 발생
    정상적으로 함수 종료
} else {
    Failure가 발생
}

ㅤㅤ

그런데, result의 type이 void 이기 때문에, 이 값을 확인할 수 없다는 에러가 자꾸 발생했다.

"this function has a return type of void and cannot be used"

ㅤㅤ

당연히 void의 반환형은 null이라고 생각해서 나는 “읭?” 한 상태로 10분 넘게 이 타입이랑 싸우고 있었다.

지금 사용중인 mockito에서 null 값을 인지하지 못하는건가? 싶어서 검색을 해보고 테스트도 굴려봤는데, 딱히 그렇지는 않았다. 심지어는 dynamic 타입이라 모든 타입을 다 받아낼 수 있는데, null 이라고 못받아내는 것도 아니였다.

ㅤㅤ

그러다가 어찌어찌 void 타입의 null 대신에 그냥 null을 냅다 넣어버리면 아무런 문제가 없다는 걸 깨달았다.

ㅤㅤ

void 타입의 null이랑 일반적인 null이랑 다른거라고??

ㅤㅤ

 

그래서 Dart 에서의 void 가 좀 더 특별한 의미를 가지고 있는 건가 찾아보다가, 아래의 reddit 글을 발견했다.

https://www.reddit.com/r/dartlang/comments/oo65yd/does_void_mean_return_null_in_dart_or_simply_just/

ㅤㅤ

여기에서 말하기를, Dart 에서의 void 라는 타입은 “컴파일러가 이 값에 접근하지 못하게 막아주는 타입” 이라고 한다. 즉, 특정한 값은 가지고 있는데, 컴파일러 단에서 접근을 못하게 막아주는 값 타입이다.

ㅤㅤ

나는 void가 단순히 null 을 반환하거나, 조금 더 나아가서는 말그대로 아무런 값을 반환하지 않아 null 조차 반환하지 않는 그런 타입이라 이런 문제가 발생한 것이라 생각했었다. 그런데 값에 접근을 막는 타입이라니…! 아래의 예시 코드를 한 번 보자. dartpad 에 넣으면 그대로 작동한다. 혹시 궁금하면 실행해보자.

ㅤㅤ

void main() {
  final v1 = first();
  final v2 = second();
  final v3 = third();

  print(v1 as Object?);
  print(v2 as Object?);
  print(v3 as Object?);
}

void first() {}

void second() {
  return null;
}

void third() => "Hmm. this is strange";

ㅤㅤ

이렇게 아무런 값도 반환하지 않는 first 함수, null을 반환하는 second 함수, String을 반환하는 third 함수를 작성해줬다. 그 결과가 void 이기 때문에, 바로 print 함수로 접근해 값을 출력할 수는 없다. 그렇기에 타입을 Object로 강제 형변환하여 출력시켜보면, 실행 결과는 아래와 같이 나온다.

ㅤㅤ

first  >> null
second >> null
third  >> Hmm. this is strange

ㅤㅤ

첫 번째와 두 번째 함수에 대해서는 어렴풋이 그려려니 하고 생각했던 결과가 나왔지만, 세 번째 함수에서는 진짜로 void 타입을 반환하는 함수에서 String이 튀어나왔다. 😮😮😮😮😮😮

ㅤㅤ

그래서 혹시나 하는 마음으로 아래 코드도 돌려봤는데, 정말 wow 였다.

void main() {
  final void strangeValue = 3;
  print(strangeValue as Object);
}

>>>
3

ㅤㅤ

심지어 여기 글에서 찾은 결과는 더 끔찍하다

https://github.com/dart-lang/sdk/issues/53179

void f<T>(T a) {
  print(T);
  print(a.runtimeType);
  print(a);
}

void main() {
  void a = 10;
  f(a);
}

>>>
void
int
10

void 타입으로 선언한 정수값에 대해서 Generic 타입을 다루는 함수로 넘겨봤더니, 변수의 선언된 타입은 void 이지만 동적타입은 int라고 나오며, 그 값도 10이라고 정상적으로 찾아내고 있다. 자신이 어떤 타입인지도 가지고 있지만, 그저 컴파일러가 해당 변수에 접근만 못하게 막고 있는 결과를 보여준다.

ㅤㅤ

그래서

Dart에서의 void 타입은 null을 담는 타입이나 아무것도 반환하지 않는 타입이 아니라, Unaccessable-Object 타입 정도로 생각해야 할 것 같다. 반환형이 void 타입인 함수라면 항상 null만 반환하는 함수가 아니라, 그 반환값이 무의미할 것이기에 반환값에 접근하지 못하게 정해둔 함수라고 생각해야 한다.

ㅤㅤ

다시 생각해도 Wow이다. 이건 이번에 찾아보지 않았으면 끝까지 몰랐을 것 같다. 후우

샤라웃

https://www.reddit.com/r/dartlang/comments/oo65yd/does_void_mean_return_null_in_dart_or_simply_just/

320x100
Share Link
reply
반응형
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31