Przeciążanie funkcji/metod - przydatne, czy nie?

0

Dylemat filozoficzno-moralny. ;)
Czy tworząc funkcję/metodę robiącą to samo, co już istniejąca, lecz przyjmująca dodatkowe parametry, nadajecie jej nową nazwę, czy przeciążacie już istniejącą?
Ja ostatnio doszedłem do wniosku, że lepiej nadać nową nazwę, dokładnie sugerującą "odmienność" nowej funkcji, dzięki temu staje się bardziej widoczna. A co Wy o tym sądzicie?

0

ja sądzę, na wzór M$a :P, że jak robi to samo to po co nazywać inaczej. Inna sprawa, że np. delphi ma parametry z domyślną wartością a np. c# nie i tam po prostu trzeba zrobić tyle metod ile różnych kombinacji parametrów do podania.

PS dał byś sondę :)

0

ja sądzę, na wzór M$a :P, że jak robi to samo to po co nazywać inaczej.

Ja sądzę, nie wiem na wzór kogo, że jak robi to samo to po co tworzyć drugą funkcję.

Inna sprawa, że np. delphi ma parametry z domyślną wartością a np. c# nie i tam po prostu trzeba zrobić tyle metod ile różnych kombinacji parametrów do podania.

Named and Optional Arguments

0

Jak robi to samo to po co dodatkowe parametry?
A jak robi cos innego to powinna sie inaczej nazywac :)

0

Uważam, że

public Object funkcja( Object[] objects, int len) {
     ...
}

public Object funkcja( Objects[] objects) {
     return this.funkcja( objects, objects.length );
}

jest jednak bardziej widoczne od

public Object funkcja_params_tablica_i_jej_dlugosc( Object[] objects, int len) {
     ...
}

public Object funkcja_param_tablica( Objects[] objects) {
     return this.funkcja_params_tablica_i_jej_dlugosc( objects, objects.length );
}
0

@kult - przykład z księżyca.
Pierwszy kod - co to za 'funkcja' i co ma robić? Przede wszystkim nie powinna nazywać się funkcja. Takie przeciążenie (object[], int) i byte[] wygląda bezsensownie (na logikę starczyłaby funkcja(object[]) sama sobie biorąca objects.Length), bez konkretnego przykładu nie ma jak dyskutować.
Drugi kod - przerysowany celowo, prowadź rzeczową argumentację :].

0
abrakadaber napisał(a):

PS dał byś sondę :)

Jakbym dał sondę, to by ludzie klikali zamiast napisać coś mądrego. A ja chętnie poczytam, jak się na to zapatrujecie. :)

n0name_l napisał(a):

Jak robi to samo to po co dodatkowe parametry?
A jak robi cos innego to powinna sie inaczej nazywac :)

Czyli jednak wyraziłem się niejasno. ;P

Załóżmy, że mamy funkcję zapisującą dane jakiegoś obiektu (np. klienta) do pliku:

void Save(string fileName, Client[] clients)

I drugą jej wersję, która pozwala na wybranie pól klasy klient, które mają być zapisane:

void SaveByFields(string fileName, Client[] clients, string[] selectedFields)

Albo funkcje odczytujące obiekt z repozytorium:

Client GetById(int id)
Client GetByName(string name)

W obu przypadkach można przeciążyć funkcje, tylko co na tym zyskujemy, a co na tym tracimy?
Wiem, przykłady strasznie proste, ale przy 5-8 parametrach i 6 przeciążeniach robi się to dość skomplikowane.

@kult, nie chodziło mi o zapisywanie w nazwie funkcji jej parametrów, lecz o krótkie sprecyzowanie jej nazwy.

0

To chyba właśnie o to chodziło w przeciążeniach aby nie precyzować nazwy. Masz dokumentację i podpowiadanie składni. Do czego ma się przydać precyzowanie nazwy? Konstruktor klasy także ominiesz na rzecz różnych metod inicjalizacji?

0
msm napisał(a):

@kult - przykład z księżyca.
Pierwszy kod - co to za 'funkcja' i co ma robić? Przede wszystkim nie powinna nazywać się funkcja. Takie przeciążenie (object[], int) i byte[] wygląda bezsensownie (na logikę starczyłaby funkcja(object[]) sama sobie biorąca objects.Length), bez konkretnego przykładu nie ma jak dyskutować.
Drugi kod - przerysowany celowo, prowadź rzeczową argumentację :].

Odbierasz dane z socketa, masz zdefiniowany rozmiar bufora odbiorczego, read nie może odczytać więcej niż mu miejsca w buforze podajesz, więc wypełnia bufor do wielkości mniejszej lub równej objętości podanej tablicy i zwraca Ci ilość wpisanych danych. Dane dalej przesyłasz do analizy, ale nie tylko z tego źródła. Taki przykładzik.

1

@somekind ale po co szukać bezsensownych przykładów - w dokumentacji c# czy delphi masz od groma przeciążonych metod, choćby

public static DirectoryInfo CreateDirectory(string path)

i
<code class="c#">public static DirectoryInfo CreateDirectory(string path, DirectorySecurity directorySecurity)

czy lepiej by było
public static DirectoryInfo CreateDirectory(string path)

i
<code class="c#">public static DirectoryInfo CreateDirectoryWithSecurity(string path, DirectorySecurity directorySecurity)

?? Nie sądzę.
Tak samo to Twoje GetByName i GetById wg mnie jest zbędne rozbijanie tego na dwie RÓŻNE metody bo one koniec, końców robią dokładnie to samo - zwracają jeden konkretny obiekt Client. Natomiast Save i SaveByFields to są dwie różne metody i robią też różne rzeczy - jedna zapisuje cały obiekt a druga tylko wybrane pole

Jeszcze tak odnośnie c# - tam dość często spotykam po 4-6 przeciążonych metod. Bardzo dobrze jest to widoczne w metodach graficznych, np DrawString - chciałbyś każdą nazywać inaczej?

Myślę, że tutaj tak jak i wszędzie potrzebne jest po prostu zdroworozsądkowe podejście do tematu

4

Sam kiedyś pisałem osobne funkcje, bo myślałem, że to lepiej widoczne jest itd...
do czasu gdy napisałem trzy te same funkcje w dużym projekcie bo ich nie widziałem :D

Przeciążenia nie masz szansy przegapić, zaś nową funkcję z nową nazwą jak najbardziej szansę masz przegapić.
Wniosek? Korzystać z przeciążeń.

0
abrakadaber napisał(a):

Tak samo to Twoje GetByName i GetById wg mnie jest zbędne rozbijanie tego na dwie RÓŻNE metody bo one koniec, końców robią dokładnie to samo - zwracają jeden konkretny obiekt Client. Natomiast Save i SaveByFields to są dwie różne metody i robią też różne rzeczy - jedna zapisuje cały obiekt a druga tylko wybrane pole

iterator erase (const_iterator position);
iterator erase (const_iterator first, const_iterator last);

Tutaj tez sa 2 rozne metody, jedna usuwa jeden element, druga ciag elementow, mimo to maja taka sama nazwe bo OBIE usuwaja.

Co do przykladow @somekind w obu przypadkach bym uzyl przeciazania.

0

Ja też bym wolał je przeciążyć - i tak podpowiada nam IDE możliwe parametry i nie trzeba szukać tego po dokumentacji. Chociaż jeśli ma to być np. coś z przedrostkiem get to chyba lepiej jednak zastosować nazwę, może nie tyle ze względu na trudność wybrania metody, ale na to, że bardzo prawdopodobne, że przeciążenie się nie uda np. przez te same typy.
Wracając do wspomnianych parametrów domyślnych w c# zostały wprowadzone od 4.0 więc i z nich można korzystać, dodatkowo podając nazwę parametru można pominąć kolejność, lub nadać jedynie ten który jest wymagany bez potrzeby uzupełniania pozostałych.

0
abrakadaber napisał(a):

Tak samo to Twoje GetByName i GetById wg mnie jest zbędne rozbijanie tego na dwie RÓŻNE metody bo one koniec, końców robią dokładnie to samo - zwracają jeden konkretny obiekt Client.

Jeśli będą się nazywały tak samo, to skąd będziesz wiedział, czy Get(string) wyszukuje po imieniu, opisie czy np. nazwie ulicy adresu zameldowania? Będziesz polegał na nazwie parametru, która może być błędna?

Bardzo dobrze jest to widoczne w metodach graficznych, np DrawString - chciałbyś każdą nazywać inaczej?

W takim przypadku akurat nie.

Natomiast Save i SaveByFields to są dwie różne metody i robią też różne rzeczy - jedna zapisuje cały obiekt a druga tylko wybrane pole

No właśnie... A ja często widzę w takich przypadkach metody przeciążone.

0
somekind napisał(a):
abrakadaber napisał(a):

Tak samo to Twoje GetByName i GetById wg mnie jest zbędne rozbijanie tego na dwie RÓŻNE metody bo one koniec, końców robią dokładnie to samo - zwracają jeden konkretny obiekt Client.

Jeśli będą się nazywały tak samo, to skąd będziesz wiedział, czy Get(string) wyszukuje po imieniu, opisie czy np. nazwie ulicy adresu zameldowania? Będziesz polegał na nazwie parametru, która może być błędna?
Nie da się przeciążyć taką samą ilością parametrów takiego samego typu więc tutaj fizycznie się nie da (a przynajmniej ja nie znam języka, który pozwalał by przeciążać na podstawie nazwy parametrów)

4

Przede wszystkim, jeśli mamy dwie przeciążone metody, gdzie typy parametrów są ze sobą zgodne w sensie rzutowania w jedną stronę lub niejawnej konwersji, to może być spory problem. Dla przykładu kod:

class Sprawdzacz
{
    boolean isString(Object o)
    {
        return false;
    }
    
    boolean isString(String s)
    {
        return true;
    }
}
 
class Main
{
        public static void main (String[] args) throws java.lang.Exception
        {
                System.out.println(new Sprawdzacz().isString("ala ma kota"));
                System.out.println(new Sprawdzacz().isString((Object)"ala ma kota"));
        }
}

Da wynik:

true
false

http://ideone.com/q5GzVQ

W wielu językach wynik będzie taki sam.

0

@Wibowit w takich okolicznościach możesz wykorzystać operator instanceof

class Sprawdzacz
{
    boolean isString(Object o)
    {
        if ( o instanceof String ) {
             return true;
        }
        else {
            return false;
        }
    }
 
    boolean isString(String s)
    {
        return isString( (Object)s );
    }
}
 
class Main
{
        public static void main (String[] args) throws java.lang.Exception
        {
                System.out.println(new Sprawdzacz().isString("ala ma kota"));
                System.out.println(new Sprawdzacz().isString((Object)"ala ma kota"));
        }
}

Chociaż i tak uważam, że przeciążenia powinny być wykorzystywane tylko dla identycznie działających metod z różnymi argumentami. W innym przypadku naturalne staje się stworzenie innej nazwy.

0
Wibowit napisał(a):

Przede wszystkim, jeśli mamy dwie przeciążone metody, gdzie typy parametrów są ze sobą zgodne w sensie rzutowania w jedną stronę lub niejawnej konwersji, to może być spory problem. Dla przykładu kod:

class Sprawdzacz
{
    boolean isString(Object o)
    {
        return false;
    }
    
    boolean isString(String s)
    {
        return true;
    }
}
 
class Main
{
        public static void main (String[] args) throws java.lang.Exception
        {
                System.out.println(new Sprawdzacz().isString("ala ma kota"));
                System.out.println(new Sprawdzacz().isString((Object)"ala ma kota"));
        }
}

Da wynik:

true
false

> http://ideone.com/q5GzVQ
> 
> W wielu językach wynik będzie taki sam.

Nie czytalem calego watku, ale sprobuj taki kod uruchomic w Groovym, lub np. w Clojure, w ktorym mozesz sobie w bardzo latwy sposob zaimplementowac multiple dispatch (w tym przypadku double; hint: multimethods).

1 użytkowników online, w tym zalogowanych: 0, gości: 1