Wygląda na to, że wszystkie nowe języki programowania lub przynajmniej te, które stały się popularne, korzystają z wnioskowania o typach. Nawet Javascript dostał typy i wnioskowanie o typach przez różne implementacje (Acscript, maszynopis itp.). Wygląda mi to świetnie, ale zastanawiam się, czy są jakieś kompromisy lub dlaczego powiedzmy, że Java lub stare dobre języki nie mają wnioskowania typu
- Deklarując zmienną w Go bez określania jej typu (używając var bez typu lub składni: =), typ zmiennej jest wywnioskowany z wartości po prawej stronie.
- D umożliwia pisanie dużych fragmentów kodu bez zbędnego określania typów, tak jak robią to języki dynamiczne. Z drugiej strony, wnioskowanie statyczne dedukuje typy i inne właściwości kodu, dając to, co najlepsze zarówno ze świata statycznego, jak i dynamicznego.
- Silnik wnioskowania typu w Rust jest dość inteligentny. Robi więcej niż patrzenie na typ wartości r podczas inicjalizacji. Wygląda również, jak zmienna jest później używana do wnioskowania o jej typie.
- Swift korzysta z wnioskowania o typie, aby opracować odpowiedni typ. Wnioskowanie typu umożliwia kompilatorowi automatyczne wydedukowanie typu określonego wyrażenia podczas kompilowania kodu, po prostu poprzez sprawdzenie podanych wartości.
programming-languages
type-systems
Użytkownik bez kapelusza
źródło
źródło
var
ponieważ może to czasem zaszkodzić czytelności.var
i C ++auto
) i wnioskowanie o typie (dwukierunkowe, jak Haskelllet
). W pierwszym przypadku typ nazwy można wywnioskować tylko z jego inicjatora - jego użycie musi być zgodne z typem nazwy. W tym drugim przypadku typ nazwy można również wywnioskować z jego użycia - co jest użyteczne, ponieważ można pisać po prostu[]
dla pustej sekwencji, niezależnie od typu elementu, lubnewEmptyMVar
dla nowego, zmiennego odwołania, niezależnie od odnośnika rodzaj.Odpowiedzi:
System typów Haskella jest w pełni nie do zniesienia (pomijając rekurencję polimorficzną, pewne rozszerzenia językowe i przerażające ograniczenie monomorfizmu ), ale programiści wciąż często dostarczają adnotacje typu w kodzie źródłowym, nawet jeśli nie muszą. Czemu?
map :: (a -> b) -> [a] -> [b]
. Jego bardziej ogólna forma (fmap :: Functor f => (a -> b) -> f a -> f b
) dotyczy wszystkichFunctor
s, nie tylko list. Uznano jednak, żemap
dla początkujących będzie to łatwiejsze do zrozumienia, dlatego żyje wraz ze swoim większym bratem.Ogólnie rzecz biorąc, wady systemu o typie statycznym, ale nie do zniesienia są w dużej mierze takie same, jak wady pisania statycznego w ogóle, zużyta dyskusja na tej stronie i innych (Googling „wady statycznego pisania” przyniesie setki stron wojen ogniowych). Oczywiście, niektóre z tych wad zostały złagodzone przez mniejszą liczbę adnotacji typu w systemie niższym. Co więcej, wnioskowanie na temat typu ma swoje zalety: rozwój dziurawy nie byłby możliwy bez wnioskowania na temat typu.
Java * dowodzi, że język wymagający zbyt wielu adnotacji typu staje się denerwujący, ale przy zbyt małej liczbie tracisz zalety, które opisałem powyżej. Języki, w których wnioskuje się o rezygnacji, zapewniają odpowiednią równowagę między dwoma skrajnościami.
* Nawet Java, ten wielki kozioł ofiarny, dokonuje pewnej liczby wnioskowania typu lokalnego . W takim stwierdzeniu
Map<String, Integer> = new HashMap<>();
nie musisz określać ogólnego typu konstruktora. Z drugiej strony języki w stylu ML są zazwyczaj globalnie gorsze.źródło
Functor
. Wymienia imap
częściej znają niesezonowanych Haskellerów.var
za przykład wnioskowania typu?var
jest właściwym przykładem.x
; w tym ostatnim nie ma typu do ustalenia, wszystkie typy są znane i wystarczy sprawdzić, czy wyrażenie ma sens. Różnica staje się ważniejsza, gdy przechodzisz obok trywialnych przykładów ix
jest używana w wielu miejscach; kompilator musi następnie sprawdzić krzyżowo lokalizacje, w którychx
służy do określenia 1) czy można przypisaćx
typ, aby kod sprawdził typ? 2) Jeśli tak, jaki najbardziej ogólny typ możemy mu przypisać?new HashMap<>();
składnia została dodana tylko w Javie 7, a lambda w Javie 8 pozwalają na całkiem sporo wnioskowania typu „rzeczywistego”.W języku C # wnioskowanie typu występuje w czasie kompilacji, więc koszt środowiska wykonawczego wynosi zero.
Ze względu na styl
var
jest stosowany w sytuacjach, w których ręczne określenie typu jest niewygodne lub niepotrzebne. Linq jest jedną z takich sytuacji. Innym jest:bez których powtarzałbyś swoją naprawdę długą nazwę typu (i parametry typu) zamiast po prostu mówić
var
.Użyj jawnej nazwy typu, gdy jest jawny, poprawia przejrzystość kodu.
Istnieją sytuacje, w których nie można użyć wnioskowania o typie, takie jak deklaracje zmiennych składowych, których wartości są ustawione w czasie budowy, lub gdy naprawdę chcesz, aby intellisense działało poprawnie (IDE Hackerrank nie zilustruje członków zmiennej, chyba że wyraźnie zadeklarujesz typ) .
źródło
Dobre pytanie!
I jest więcej ezoterycznych języków, które nie mogą zrobić swojej dziwności bez wyraźnej adnotacji typu. Jak dotąd nie znam żadnych, które byłyby na tyle powszechne / popularne / obiecujące, że można by o nich wspomnieć, z wyjątkiem przelotu.
źródło
var foo = x => x;
zawodzi, ponieważ język musi sięx
tutaj wywnioskować i nie ma już nic do roboty. Kiedy budowane są lambdy, są one budowane tak, jak delegaci o wyraźnym typieFunc<int, int> foo = x => x
są wbudowani w CIL tak, jakFunc<int, int> foo = new Func<int, int>(x=>x);
lambda jest generowana jako wygenerowana, wyraźnie wpisana funkcja. Dla mnie wnioskowanie o rodzajux
jestx => x
zawarte są w samej lambdzie - nie odnoszą się do żadnych zmiennych z otaczającego zakresu. Każdy rozsądny język funkcjonalny będzie poprawnie wywnioskować, że jego typ to „dla wszystkich typówa
,a -> a
”. Myślę, że DeadMG próbuje powiedzieć, że system typów C # nie ma głównej właściwości type, co oznacza, że zawsze można znaleźć najbardziej ogólny typ dla dowolnego wyrażenia. Jest to bardzo łatwa do zniszczenia właściwość.Java jest tutaj wyjątkiem, a nie regułą. Nawet C ++ (który moim zdaniem kwalifikuje się jako „dobry stary język” :)) obsługuje wnioskowanie typu ze
auto
słowem kluczowym od standardu C ++ 11. Działa nie tylko z deklaracją zmiennej, ale także jako typ zwracanej funkcji, co jest szczególnie przydatne w przypadku niektórych złożonych funkcji szablonu.Utajone pisanie i wnioskowanie o typie ma wiele dobrych przypadków użycia, a są też przypadki użycia, w których naprawdę nie powinieneś tego robić. Czasami jest to kwestia gustu, a także temat debaty.
Ale to, że istnieją niewątpliwie dobre przypadki użycia, jest samo w sobie uzasadnionym powodem dla każdego języka, aby go wdrożyć. Nie jest to również trudne do zaimplementowania, nie ma ujemnego wpływu na środowisko uruchomieniowe i nie wpływa znacząco na czas kompilacji.
Nie widzę prawdziwej wady polegającej na tym, że daje programistom możliwość wnioskowania o typie.
Niektórzy odpowiadający zastanawiają się, jak dobre jest pisanie na klawiaturze, i na pewno mają rację. Ale brak obsługi niejawnego pisania oznaczałoby, że język wymusza ciągłe pisanie przez cały czas.
Tak więc prawdziwą wadą jest to, że język nie obsługuje niejawnego pisania, ponieważ oznacza to, że nie ma uzasadnionego powodu, aby użyć go, co nie jest prawdą.
źródło
Podstawową różnicą między systemem wnioskowania typu Hindleya-Milnera i wnioskowania typu Go jest kierunek przepływu informacji. W HM typ informacji przepływa do przodu i do tyłu poprzez unifikację; w Go wpisz informacje przepływa tylko do przodu: oblicza tylko substytucje do przodu.
Wnioskowanie o typach HM jest wspaniałą innowacją, która dobrze działa z językami funkcjonalnymi o typie polimorficznym, ale autorzy Go prawdopodobnie twierdzą, że próbuje zrobić zbyt wiele:
Fakt, że informacja przepływa zarówno do przodu, jak i do tyłu oznacza, że wnioskowanie o typie HM jest bardzo nielokalną sprawą; przy braku adnotacji typu, każdy wiersz kodu w twoim programie może przyczyniać się do pisania pojedynczego wiersza kodu. Jeśli masz tylko podstawianie do przodu, wiesz, że źródłem błędu typu musi być kod poprzedzający błąd; nie kod, który pojawia się po.
Dzięki wnioskowaniu typu HM masz tendencję do myślenia w ograniczeniach: kiedy używasz typu, ograniczasz jego możliwe typy. Na koniec dnia mogą istnieć pewne zmienne typu, które są całkowicie nieograniczone. Wnioskowanie o typach HM polega na tym, że te typy naprawdę nie mają znaczenia, dlatego są one przekształcane w zmienne polimorficzne. Jednak ten dodatkowy polimorfizm może być niepożądany z wielu powodów. Po pierwsze, jak zauważyli niektórzy, ten dodatkowy polimorfizm może być niepożądany: HM zawiera fałszywy, polimorficzny typ jakiegoś fałszywego kodu, a później prowadzi do dziwnych błędów. Po drugie, gdy typ zostanie pozostawiony polimorficzny, może to mieć konsekwencje dla zachowania środowiska wykonawczego. Na przykład zbyt polimorficzny wynik pośredni jest powodem, dla którego „pokaż. read jest uważany za niejednoznaczny w Haskell; jako inny przykład
źródło
Utrudnia to czytelność.
Porównać
vs
Jest to szczególnie problem podczas czytania poza IDE, jak na github.
źródło
var
możesz z niej korzystać bez uszczerbku dla czytelności.var objects = GetBusinessObjects();