Jedna funkcja w wielu wersjach

2011-03-10 18:12

Wytykanie niedoskonałości i różnego rodzaju felerów języka C++ to jedno z ulubionych zajęć niektórych programistów, zwłaszcza tych którzy z jakichś powodów muszą z tego języka korzystać. Sam czasami to robię, ale dzisiaj chcę zwrócić uwagę na to, co C++ robi dobrze – albo przynajmniej lepiej niż w wielu innych, popularnych językach. A chodzi tu o swobodę w definiowaniu wielu wersji tej samej funkcji, różniących się listą parametrów. Nazywa się to zwykle przeciążaniem, chociaż nie jest to jedyny sposób na osiągnięcie takiego efektu.

Innym są bowiem parametry domyślne i istnieje przynajmniej jeden język, w którym jest to sposób jedyny. Tak jest bowiem w Pythonie i nawet czasami ma to sens, biorąc pod uwagę brak deklarowanych typów w tym języku. Jednak równie często wymaga to czegoś w stylu samodzielnego rozstrzygania przeciążania już wewnątrz funkcji:

  1. def some_func(string_or_list):
  2.     if isinstance(string_or_list, list): x = "".join(string_or_list)
  3.     elif isinstance(string_or_list, basestring): x = string_or_list
  4.  
  5.     # ...

Powyższe ify to nic innego jak boilerplate code: redundantne, powtarzalne fragmenty kodu, które w dodatku robią tutaj to, co w innych językach spoczywa na barkach kompilatora. Usprawiedliwieniem może być pewnie to, że przecież Python nie jest kompilowany ;P

Ale jak wspomniałem wcześniej, język spod znaku węża posiada możliwość definiowania argumentów domyślnych, za co należy mu oddać honor. Niestety nie da się tego powiedzieć o kilku innych, popularnych dziś językach, jak choćby C# i Javie. Jeśli chcemy mieć w nich dwie sygnatury tej samej metody, musimy ją przeciążyć. Otrzymujemy wtedy dwie wersje (lub więcej), z których jedna – ta posiadająca mniej argumentów – jest po prostu wywołaniem drugiej. Widuje się to często w konstruktorach, z których czasem układa się swego rodzaju sztafeta wywołań:

  1. public Foo() { this(0); }
  2. public Foo(int x) { this(x, null); }
  3. public Foo(int x, Object o) { this(x, o, ""); }
  4. public Foo(int x, Object, String s) {
  5.     // właściwy konstruktor
  6. }

Jak łatwo zauważyć, jest ona wybitnie rozwlekła, trudna w utrzymaniu i modyfikacji, a także mało czytelna, gdyż wartości domyślne argumentów są ukryte w wywołaniach zamiast w deklaracjach funkcji. Jej odpowiednik z argumentami domyślnymi byłby natomiast krótki, przejrzysty, zrozumiały i łatwy do ewentualnej zmiany.

“Problem” z tworzeniem wielu wersji funkcji polega właśnie na tym, iż mimo istnienia dwóch sposobów na osiągnięcie tego samego efektu, bardzo często jeden jest wyraźnie lepszy niż drugi. Stąd każdy język nieposiadający wsparcia dla któregoś z nich niejako z automatu kreuje sytuacje, dla których rozwiązania trzeba szukać na około.
I tu pozytywnie wyróżnia się C++, który pozwala na stosowanie obu technik (przeciążania lub argumentów domyślnych) w zależności od potrzeb. Również razem, jeśli rezultat nie powoduje niejednoznaczności w wywołaniach. Z pewnością jest to cenna cecha tego języka, równoważąca znaczącą część jego znanych niedostatków :)

Tags: , , , , ,
Author: Xion, posted under Programming »


4 comments for post “Jedna funkcja w wielu wersjach”.
  1. vashpan:
    March 10th, 2011 o 18:44

    C# 4.0 umozliwa definiowanie argumentow domyslnych, podobnie jak w C++ :)

  2. Xion:
    March 10th, 2011 o 20:49

    Serio? No to w końcu widać rzeczywisty postęp w tym języku :))

  3. czepialski:
    March 10th, 2011 o 23:19

    Wiem, że to tylko przykład ale twoim Pythonowym kodzie wystarczy napisać:

    def some_func(iterable):
    x = “”.join(iterable)
    #…

    Jak sie okazuje sprytne konstruowanie funkcji w Pythonie może czasem zastąpić przeciążanie ;)

  4. vashpan:
    March 11th, 2011 o 12:20

    @xion W C# 4.0 Dodatkowo jeszcze sa nazywane argumenty, podobnie jak w Pythonie. W sumie tego mi brakuje w C++ jezeli chodzi o ten, bardzo zreszta slusznie chwalony przez ciebie “feature”

Comments are disabled.
 


© 2017 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.