민스씨의 일취일장

Dart | Flutter | VoidCallback vs. Function 본문

Mobile/Flutter & Dart

Dart | Flutter | VoidCallback vs. Function

읻민스 2025. 10. 23. 22:56
반응형

VoidCallback과 Function에 대해 비교하는 글이다.

VoidCallback vs. Function

Dart & Flutter - VoidCallback vs. Fuction 비교하기 썸네일 이미지이다.
Dart & Flutter - VoidCallback vs. Fuction 비교하기

VoidCallBack vs. Function

위젯을 만들 때, 상위 위젯에서 메서드를 전달해 주는 경우가 있다. 그런데 어떤 경우에는 VoidCallback 타입의 메서드를, 또 어떤 경우에는 Function 타입의 메서드를 전달하는 경우가 있다. 이 둘이 어떤 차이가 있는지 한 번 알아보았다.

VoidCallback

typedef VoidCallback = void Funcation();

 

VoidCallback은 아무 인자도 받지 않고, 아무것도 반환하지 않는 함수 타입이다. 주로 Flutter 프레임워크에서 onPressed, onTap등에 사용된다.

  • 장점

타입이 명확하기 때문에 IDE와 컴파일러가 Syntax 에러를 쉽게 찾아 줄 수 있다. 또한 명확성(어떤 동작을 하고 어떤 데이터가 필요한지 명확)과 일관성(클릭, 탭등 같은 종류의 동작에 대해 항상 같은 형태의 콜백 메서드를 제공)을 중요하게 생각하는 Flutter 위젯 설계 철학에 부합한다.

  • 단점

인자를 전달해야 하거나, 반환값이 필요한 경우에는 사용할 수 없다는 단점이 있다.

Function

모든 형태의 함수를 받을 수 있는 타입이다. 인자가 있어도 되고, 없어도 되며, 반환값도 있어도 되고 없어도 된다. 말그대로 원래 알고 있는 보편적인 메서드이다.

  • 장점

어떤 상황에서도 사용할 수 있다.

  • 단점

타입이 명확하지 않아서, IDE의 도움을 받는데 제한이 있다. 또한 잘못된 형태의 함수가 전달되어도 컴파일 단계에서 알 수 없다.

Flutter 이벤트 핸들러는 무저건 VoidCallback?

이 둘을 알아 보니 자연스럽게, 'Flutter 이벤트 핸들링(Callback Property)을 할 때는 무조건 VoidCallback을 쓰면 될까?'하는 의문이 들었다. 정답은 아니다. 왜냐하면 위의 2가지 외에 3가지 타입의 메서드가 더 있기 때문이다.

AsyncCallback

typedef AsyncCallback = Function<void> Function();

 

AysncCallback은 VoidCallback에 비동기성이 추가된 메서드 타입이다. 응답 대기 즉, await가 필요한 곳에서 사용할 수 있다.

ValueChanged<T>

typedef ValueChanged<T> = void Function(T value);

 

ValueChanged<T>는 인자를 하나 받아서 처리하는 콜백메서드 타입이다. 주로 onChanged의 콜백 프로퍼티에 사용되며, 값이 변경된 것을 "전달"할 의도로 사용한다.

ValueSetter<T>

typedef ValueSetter<T> = void Function(T value);

 

ValueSetter<T>는 ValueChanged<T>와 마찬가지로 인자를 하나 받아서 처리하는 콜백메서드 타입니다. 하지만 차이점은 변경된 값을 "반영"할 의도로 사용한다는 점이다.

ValueChanged<T> vs. ValueSetter<T>

타입은 다르지만, 본질적으로 void Function(T)로 같은 형태를 가지고 있다.

정리

Flutter 위젯의 이벤트를 핸들링 할 때는 위의 5가지 타입 중, Function을 제외한 4가지 (VoidCallback, AsyncCallback, ValueChanged<T>, ValueSetter<T>)를 상황에 맞게 사용하는 것이 권장된다. 반대로 Function은 너무 범용적이기 때문에 권장되지 않는다. (하지만 불가능 하지는 않다.)

어차피 다 Function 아닌가?

그런데 여기까지 공부하고 보니, 뭔가 찝찝하다. 어차피 다 Fucntion 아닌가?

이 점에 대해서도 알아보았더니, 먼저 위에서 살펴본 Function 외 4가지 타입은 "함수 타입 Alias"일 뿐이다. 즉, 특수한 케이스(typedef)를 명시적으로 구분하기 위해서 이름을 붙여준 것이다.

typedef VoidCallback = void Function();
typedef AsyncCallback = Future<void> Function();
typedef ValueChanged<T> = void Function(T value);
typedef ValueSetter<T> = void Function(T value);

 

따라서 아래의 두 문장은 완벽히 동일하다.

final void Function() onPressed;
final VoidCallback onPressed;

그럼 왜 굳이 별도의 타입을 만들어 놓은 것일까?

이유는 "의도를 코드에 담기 위해"서이다. 타입만 보아도 어떤 역할을 하는지 알수 있도록 말이다. 따라서 typedef는 단순한 syntax가 아니고 'context'를 담기 위한 언어적 장치라고도 할 수 있다. 이 때문에 코드의 직관적 가독성이 높아지기 때문이다. 단지 그 높아진 가독성을 느끼기 위해선, 해당 개념을 알고 있어야만 한다는 맹점(?)이 있긴 하다.

이런 개념은 Dart에만 있는 것인가?

이런 함수타입을 이번에 처음 알게되었다. 본적은 있었겠지만, 그냥 메서드 이고 이름을 보면 대충 이해는 할 수 있었기 때문에 진지하게 알아볼 기회가 많지 않았다. 그래서 이런 개념이 Dart에만 있는 것인지 알아보았더니, 다른 언어에도 많이 존재한다는 것을 알게되었다. 그리고 또하나는 ydmins는 Java를 주로 공부했었는데, Java는 때마침 이런 기능을 제공하지 않는다. (대신 functional interface라는 개념을 구현한다고 한다.) 그래서 더욱더 이런 개념이 낯설었던 것이었다.

마무리

  • Function Alias
    • 총 4가지 VoidCallback / AsyncCallBack / ValueChanged / ValueSetter의 함수 특수 타입이 존재한다.
    • 이는 코드의 명확성을 높이며, Context를 담아 가독성을 높이는데 도움을 준다.
    • 하지만 본질적으로 Function과 같다. 

 

728x90
반응형