2009-10-20 14 views
9

c, java i wiele innych języków nie zwracają uwagi na wartości zwracane.Dlaczego języki nie zezwalają na przeciążanie metod przez zwracaną wartość?

int i = func() 
float f = func() 
int func() { return 5 } 
float func() { return 1.3} 

Dlaczego nie jest to zgodne z prawem? Czy to utrudnia programowanie Czy trudno jest napisać kompilator? czy jest więcej jednoznaczności językowej? Czy istnieje język, który potrafi to zrobić?

+0

Czy próbowałeś LISP? Jeśli nie, spróbuj, może to rozwiązać twój problem. – Zinx

+0

możliwy duplikat funkcji [Przeciążenie funkcji według typu zwrotu?] (Http://stackoverflow.com/questions/442026/function-overloading-by-return-type) – nawfal

Odpowiedz

14

Powiedzmy to pozwolono, co jeden to wezwanie:

func(); 

To nie niech pełnej odpowiedzi, ale uważam, że to jeden z powodów, dlaczego to nie jest legalne.

+1

To dobra uwaga. Parametry są zwykle wymagane w przypadku funkcji, ale obsługa wartości zwracanej nie jest wymagana. – Herms

+2

Myślę, że niewłaściwą praktyką jest nie obsługiwać zwracanych wartości. Powinno to być nieważne, wyrzucać wyjątek lub sprawdzić wartość zwracaną. Jednak var v = func(); (Przypisanie stylu w stylu C#) może powodować problemy ... (hmmmm)) –

+0

+1 za przyznanie mi v v = powyżej –

17

Co z tą sprawą?

class A implements Foo { /*...*/ } 
class B implements Foo { /*...*/ } 

A func() { return new A(); } 
B func() { return new B(); } 

Foo v = func(); // which do you call?! 

Istnieją już problemy z niejednoznaczności gdy pozwalasz przeciążenia pojedynczej nazwy funkcji, które podjąć różne argumenty. Konieczność sprawdzenia również typu zwrotu prawdopodobnie sprawi, że rozwiązanie właściwej funkcji będzie znacznie trudniejsze.

Jestem pewien, że język mógłby to zaimplementować, ale sprawiłoby, że sprawy byłyby o wiele bardziej skomplikowane i generalnie sprawiłoby, że kod byłby trudniejszy do zrozumienia.

+2

Podobnie powinno być "System.out.println (func () + func()) 'wyjście? – notnoop

+0

To utrudniłoby zrozumienie kodu. +1. Może oznaczyę to jako poprawne (chcę zobaczyć inne odpowiedzi)? –

+0

Jak wymagać zaznaczenia jednego z przeciążeń jako "preferowany", a inne są używane tylko wtedy, gdy typ zwrotu zostanie natychmiast rzucony lub wymuszony na inny typ (dla którego zapewnione jest dokładniejsze przeciążenie) lub gdy typ zwracanego sygnału jest ignorowany (w takim przypadku, jeżeli zostanie zastosowane przeciążenie typu "void", jeśli zostanie dostarczone)? – supercat

6

Na przykład C++, należy rozważyć:

void g(int x); 
void g(float x); 
g(func()); 

Które z funkcji przeciążonych g() byłoby nazwać?

+1

w tym przypadku może zrobić to, co C++ czasami i kompiluje z niejednoznacznym błędem zmuszając użytkownika do napisania 'g ((Float_OR_int_type) func());' –

+0

Nawet to nie pomogło. Co się stanie, jeśli masz wiele metod, które zwracają typ, który może być rzetelnie rzutowany na obiekt, który przesyłasz? int może być rzutowany, a na odwrót. – Herms

1

Większość języków zezwala na operacje w trybie mieszanym z automatycznym wymuszaniem (na przykład float + int), w których wiele interpretacji jest legalnych. Bez przymusu praca z wieloma typami numerycznymi (krótkimi, int, long, float, double) stałaby się bardzo uciążliwa; dzięki przymusowi, disambigation oparty na typie powrotnym doprowadziłby do trudnego do zrozumienia kodu.

1

Pozwolenie na to może powodować problemy. Na przykład:

int i = func2(func()); 
int func() { return 5; } 
float func() { return 1.3; } 
int func2(float a) { return a; } 
int func2(int a) { return a; } 

Jest to wieloznaczne.

+0

Co byłoby nie tak z określeniem, że każdy podpis metody musi mieć jedną implementację, która jest oznaczona jako preferowana, z wyjątkiem sytuacji, gdy wynik funkcji był przypisany do zmiennej lub natychmiastowego typowania? – supercat

3

Perl pozwala na pewien stopień zmiany typu zwrotu, ponieważ funkcje mogą określać rodzaj kontekstu, w którym są oceniane. Na przykład funkcja, która może zwrócić tablicę, może zobaczyć, że działa w kontekście skalarnym, i po prostu zwracaj domniemaną długość bezpośrednio, oszczędzając przydział i inicjalizację tablicy, aby uzyskać jej długość.

+0

Co działa dla Perla, ale w Perlu jest kilka rzeczy, które nie będą działały w bardziej konwencjonalnym języku. Nie wspominając o tym, że Perl nie ma systemu typów w normalnym znaczeniu: typy to $ skalars, @arrays, #hashes, @typeglobs i wydaje mi się, że zapomniałem. Nie ma rozróżnienia między liczbą całkowitą, zmiennoprzecinkową i ciągiem znaków, a operatorzy muszą określić, czy mają działać numerycznie ($ i + 1), czy też łańcuchami ($ i + "1"). –

+0

@David: Nie sądzę, żebym chwalił jakieś zalety Perla w mojej odpowiedzi, ani sugerowanie, że takie rzeczy * powinny * być dodawane do innych języków. Po prostu odpowiadałem na część pytania, które pyta, co tam jest. – Novelocrat

10

Tak, zezwalanie na przeciążanie typów zwrotów komplikuje język. To komplikuje rozwiązywanie przeciążonych identyfikatorów (np. Nazw funkcji). Ale nie jest to niemożliwe, np. Haskell pozwala na przeciążenie funkcji w zależności od ich typu zwrotu.

class Num a where 
    fromInteger :: Integer -> a 
    ... 

Num jest klasa typu Haskell z metodą zwaną fromInteger którym funkcja z dowolnego rozmiaru Integer do dowolnego typu, który ma instancję Num. Mechanizm klasy typu Haskell różni się nieco od koncepcji klasowej języków obiektowych. Dlatego moje wyjaśnienie może zabrzmieć dziwnie.

Ale wynikiem tego jest możliwość użycia funkcji fromInteger i, w zależności od kontekstu wywołującego, różne implementacje są wybierane podczas kompilacji.

Istnieje cała seria badań systemów typów, dzięki którym ta funkcja jest możliwa. Dlatego powiedziałbym, że jest to wykonalne w statycznie napisanych językach. Dynamicznie napisane języki wymagałyby podróży w czasie lub sprytnych pomysłów.

9

Aby uniknąć niejednoznaczności.

a(int) 
a(bool) 
int b() 
bool b() 

a(b()) -- Which b? 

Tu typ wnioskowania ma cykliczną zależność. Który z numerów b zależy od tego, który z nich zależy od tego, który z nich jest zablokowany.

Niedozwolone przeciążanie typów zwracanych zapewnia, że ​​wnioskowanie o typ jest acykliczne. Typ powrotu może zawsze być określony przez typy parametrów, ale typy parametrów nie mogą być określone przez typ zwracany, ponieważ mogą one być z kolei określone przez typy parametrów, które próbujesz znaleźć.

+1

+1 za naprawdę miły, zwięzły, bezpośredni przykład. –

+1

+1 za podanie inferencji typu –

+0

Istnieje wiele niejednoznacznych sytuacji, ale to nie oznacza, że ​​przeciążenie nie może być użyteczne, jeśli (1) należy użyć jakiejś "podstawowej" funkcji, z wyjątkiem przypadków, w których inna była wyraźnie lepsza, i (2) w przypadkach, które nadal byłyby niejednoznaczne, kompilator mógłby użyć albo. Rozważ funkcje (int32, int32) -> int32, (int32, int32) -> int64 i (int64, int64) -> int64. Jeśli zachowują semantycznie identyczne zachowanie w przypadkach, w których obliczona wartość byłaby w obrębie klasy int32, kompilator mógłby używać (int64, int64) -> int64 zawsze, ale wydajność mogłaby być lepsza, gdyby zamiast tego użyto (int32, int32) -> int32. – supercat

Powiązane problemy