What is function overloading?
Function overloading, birçok programlama dilinde mevcut olan bir özelliktir. Aynı davranışı sergileyen ve aynı adı taşıyan birden fazla fonksiyon tanımlamanıza olanak tanır. Derleyici tarafından parametre sayısı ve tipiyle birbirinden ayrıştırılır. Bu özellik sayesinde kodun kullanılabilirliği, okunabilirliğini ve esnekliği artmış olur.
Function overloading in OOP languages
Java ve C++ gibi öz hakiki OOP dillerinde ana konseptlerden biridir. Derleyici doğru fonksiyonu çağırmak için fonksiyon ismi ve parametre türlerinden oluşan signature'a bakarak karar verir.
Java example
Java'da implementasyonu aşağıdaki gibidir:
1class Notification {
2 void send(String email, String message) {
3 // ...
4 }
5
6 void send(String email, String message, boolean isUrgent) {
7 // ...
8 }
9
10 void send(String email, String subject, String body) {
11 // ...
12 }
13}
14
15public class Main {
16 public static void main(String[] args) {
17 Notification notifier = new Notification();
18
19 notifier.send("Hello!");
20 notifier.send(
21 "Reminder",
22 "The meeting time has been changed to 10 AM."
23 );
24 notifier.send(
25 "ensbaspinar@gmail.com",
26 "Can you send me the plans for the team?",
27 true
28 );
29 }
30}
C++ example
C++'da da benzer bir implementasyon mevcuttur:
1class Notification {
2public:
3 void send(const string& message) {
4 // ...
5 }
6
7 void send(const string& subject, const string& body) {
8 // ...
9 }
10
11 void send(const string& email, const string& message, bool isUrgent) {
12 // ...
13 }
14};
15
16int main() {
17 Notification notifier;
18
19 notifier.send("Hello!");
20 notifier.send(
21 "Reminder",
22 "The meeting time has been changed to 10 AM."
23 );
24 notifier.send(
25 "ensbaspinar@gmail.com",
26 "Can you send me the plans for the team?",
27 true
28 );
29}
Her iki dilde de overload resolution derleme zamanında yapılır, bu da sağlanan argümanlara göre uygun yöntemin çağrılmasını kesinleştirir.
How to handles function overloading?
- Function SignaturesDerleyici, aynı isme sahip fonksiyonların signature'larını kontrol eder. Eğer bu fonksiyonların parametre listeleri farklıysa, derleme başarılı olur; aksi takdirde derleme hatası oluşur.
- Name ManglingAynı isme sahip fonksiyonları ayırt etmek için name mangling tekniğini kullanır. Bu teknik, fonksiyon adlarını parametre türleri ve sayılarıyla birlikte kodlayarak benzersiz hale getirir. Örneğin,
vefoo(int, double)
fonksiyonlarının isimleri derleyicidefoo(double, double)
vefoo_id
olarak temsil edilir.foo_dd
- Call ResolutionFonksiyon çağrıldığında derleyici argüman türlerini kontrol eder ve uygun fonksiyonu bulur.
Function overloading in TypeScript
TypeScript, JavaScript'in statik tiplerle genişletilmiş üst kümesi olarak function overloading destekler ancak bu işlemi geleneksel OOP dillerinden farklı ele alır. Birden fazla fonksiyon signature'ı tanımlanır ancak implementasyon tek fonksiyonda yapılır.
Example
1class Notification {
2 send(message: string): void;
3 send(subject: string, body: string): void;
4 send(email: string, message: string, isUrgent?: boolean): void;
5
6 send(arg1: unknown, arg2?: unknown, arg3?: unknown): void {
7 if (typeof arg1 === "string" && !arg2 && !arg3) {
8 // ...
9 } else if (typeof arg1 === "string" && typeof arg2 === "string" && !arg3) {
10 // ...
11 } else if (typeof arg1 === "string" && typeof arg2 === "string" && typeof arg3 === "boolean") {
12 // ...
13 }
14 }
15}
16
17const notifier = new Notification();
18
19notifier.send("Hello!");
20notifier.send("Hello!");
21notifier.send(
22 "Reminder",
23 "The meeting time has been changed to 10 AM."
24);
25notifier.send(
26 "ensbaspinar@gmail.com",
27 "Can you send me the plans for the team?",
28 true
29);
Example 2
In the second example, let's see how to change the behavior in a hook we created in React.
1type Callback = () => void;
2
3export function useSeenObserver(callback: Callback): React.RefObject<HTMLElement>;
4export function useSeenObserver(selector: string, callback: Callback): void;
5export function useSeenObserver(arg1: string | Callback, arg2?: Callback): React.RefObject<HTMLElement> | void {
6 let element: Element;
7 let callback: Callback;
8 let ref = useRef<HTMLElement>(null);
9
10 if (typeof arg1 === "string") {
11 element = document.querySelector(arg1)!;
12 callback = arg2!;
13 } else {
14 element = ref.current!;
15 callback = arg1!;
16 }
17
18 // ...
19
20 if (typeof arg1 !== "string") {
21 return ref;
22 }
23}
24
25/* Usage 1 */
26const ref = useSeenObserver(() => {
27 // ...
28});
29
30/* Usage 2 */
31useSeenObserver("#component", () => {
32 // ...
33});
How to handles function overloading?
- Checking Function SignaturesFonksiyonun belirtilen signature'lardan biriyle uyumlu olup olmadığını görmek için derleme zamanında türü kontrol eder. Aynı zamanda geliştirme esnasında statik kontroller gerçekleştirerek uyumsuzluklar hakkında uyarır.
- Call ResolutionTypescript, JavaScript'e derlendiğinden dolayı type safety ve signature check işlemleri run-time'da çalışmaz. Bu sebepten ötürü fonksiyonun içerisinde parametre türlerinin koşullarla kontrol edilmesi gerekir.
Why should I use it?
Typescript'te union kullanmak yerine neden signature kullanmalıyım sorusu aklınıza gelebilir. Son örneği signature kullanmadan yeniden yazalım.
1type Callback = () => void;
2
3export function useSeenObserver(arg1: string | Callback, arg2?: Callback): React.RefObject<HTMLElement> | void {
4 let element: Element;
5 let callback: Callback;
6 let ref = useRef<HTMLElement>(null);
7
8 if (typeof arg1 === "string") {
9 element = document.querySelector(arg1)!;
10 callback = arg2!;
11 } else {
12 element = ref.current!;
13 callback = arg1!;
14 }
15
16 // ...
17
18 if (typeof arg1 !== "string") {
19 return ref;
20 }
21}
Daha sonra, `useSeenObserver' hook'unu kullandığımızda TypeScript'in önerdiği tipe ve yaptığı kontrole bakalım.
Görebileceğiniz gibi net bir function overloading template veremez. Argüman isimleri anlamsız kalır. Hangi parametrenin hangisiyle birlikte kullanılması gerektiği konusu bulanıklaşır. Aşağıdaki varyantlarda, hatalı kullanımlar da dahil, TypeScript hata vermez:
-> hatalı kullanım(arg1: string)
(arg1: string, arg2: Callback)
(arg1: Callback)
-> hatalı kullanım(arg1: Callback, arg2: Callback)
Signature kullandığınızda ise aşağıdaki gibi doğru bir API elde etmiş olursunuz.