Jedną rzeczą, która przyszła mi do głowy pewnego dnia, są wciąż potrzebne konkretne typy lub dziedzictwo, które nas powstrzymuje. Chodzi mi o to: czy naprawdę potrzebujemy krótkiej, int, długiej, bigint itp.
Rozumiem rozumowanie, zmienne / obiekty są przechowywane w pamięci, pamięć musi zostać przydzielona i dlatego musimy wiedzieć, jak duża może być zmienna. Ale tak naprawdę, czy współczesny język programowania nie powinien być w stanie poradzić sobie z „typami adaptacyjnymi”, tzn. Jeśli coś jest kiedykolwiek przydzielane tylko w krótkim zakresie, wykorzystuje mniej bajtów, a jeśli coś jest nagle przydzielane, bardzo duża liczba, pamięć jest przydzielana odpowiednio dla tego konkretnego przypadku.
Float, real i double są nieco trudniejsze, ponieważ typ zależy od wymaganej precyzji. Ciągi powinny jednak być w stanie zajmować mniej pamięci w wielu przypadkach (w .Net), w których używa się głównie ascii, ale ciągih zawsze zajmują podwójną pamięć z powodu kodowania Unicode.
Jednym z argumentów za konkretnymi typami może być to, że jest to część specyfikacji, tj. Na przykład zmienna nie powinna być większa niż pewna wartość, więc ustawiliśmy ją na skrót. Ale dlaczego nie zamiast tego mieć ograniczenia typu? Byłoby znacznie bardziej elastyczne i wydajne, aby móc ustawić dopuszczalne zakresy i wartości zmiennych (i właściwości).
Zdaję sobie sprawę z ogromnego problemu związanego z przebudową architektury typu, ponieważ jest ona tak ściśle zintegrowana z podstawowym sprzętem, a sprawy takie jak serializacja mogą stać się naprawdę trudne. Ale z punktu widzenia programowania powinno być świetnie, nie?
źródło
type hour is range 0 .. 23;
Odpowiedzi:
Całkowicie wierzę, że tak jest. Ograniczenia semantyczne są warte więcej niż ograniczenia wdrażania. Martwienie się rozmiarem czegoś wydaje się troską o szybkość czegoś, gdy powstaje programowanie obiektowe.
Nie zastąpił programowania krytycznego pod względem wydajności. Po prostu sprawiło, że programowanie krytyczne bez wydajności jest bardziej produktywne.
źródło
Typy adaptacyjne oznaczają logikę do wykonania adaptacji, oznaczają pracę w środowisku wykonawczym, aby uruchomić tę logikę (tworzenie szablonów i czas kompilacji wymagałoby określonego typu, a wnioskowanie o typ jest szczególnym przypadkiem, w którym uzyskuje się to, co najlepsze z dwóch światów). Ta dodatkowa praca może być odpowiednia w środowiskach, w których wydajność nie jest krytyczna, a system utrzymuje odpowiedni rozmiar. W innych środowiskach tak nie jest (systemy wbudowane to takie, w których czasami trzeba użyć liczb całkowitych 32/64-bitowych dla wydajności procesora i typów całkowitych 8/16-bitowych dla optymalizacji statycznej kopii zapasowej pamięci).
Nawet języki ogólnego przeznaczenia, które obsługiwały późne wiązanie (rozwiązywanie typów w środowisku wykonawczym, takie jak VB6), obecnie mają tendencję do promowania silnego pisania (VB.NET), z powodu spadku wydajności, który pojawiał się, gdy nadużycie późnego wiązania było nadużywane, i ponieważ często kończą się brzydkim kodem, gdy typy nie są jawne ( Reference / Professional Refactoring in Visual Basic - Danijel Arsenovski ).
źródło
Prostota, pamięć i szybkość Kiedy deklaruję zmienną, pamięć dla tej zmiennej jest przydzielana w jednym bloku. Aby wesprzeć dynamicznie rosnącą zmienną, musiałbym dodać pojęcie nieciągłej pamięci do tej zmiennej (albo to, albo zarezerwować największy blok, który zmienna może reprezentować). Nieprzylegająca pamięć zmniejszyłaby wydajność przy przypisywaniu / pobieraniu. Przydzielenie największego możliwego byłoby marnotrawstwem w scenariuszu, w którym potrzebuję tylko bajtu, ale system rezerwuje długo.
Pomyśl o kompromisach między tablicą a wektorem (lub połączoną listą). W przypadku tablicy wyszukiwanie określonej pozycji jest prostą sprawą, aby uzyskać pozycję początkową i przesunąć wskaźnik pamięci x spacje, aby zlokalizować tę nową pozycję w pamięci. Pomyśl o int jako trochę [32] czytanie int polega na przejściu przez tę tablicę, aby uzyskać wszystkie wartości bitów.
Aby utworzyć typ liczby dynamicznej, musisz zmienić go z tablicy bitów na wektor bitów. Odczytywanie numeru dynamicznego polega na podchodzeniu do głowy, zdobyciu tego bitu, zapytaniu, gdzie jest następny bit w pamięci, przejściu do tej lokalizacji, pobraniu tego bitu itp. Dla każdego bitu w liczbie dynamicznej wykonujesz trzy operacje odczytu ( bieżący), przeczytaj (adres następnego), przenieś (następny). Wyobraź sobie, że czytasz wartości miliona liczb. To milion dodatkowych operacji. To może wydawać się nieistotne. Ale pomyśl o systemach (takich jak finanse), w których liczy się każda milisekunda.
Podjęto decyzję, że nałożenie na programistę obowiązku sprawdzenia rozmiaru i zatwierdzenia jest niewielkim kompromisem w porównaniu z obniżeniem wydajności systemu.
źródło
Określone typy są wymagane w przypadku języków i projektów zorientowanych na sprzęt. Jednym z przykładów są protokoły sieciowe w sieci.
Ale stwórzmy - dla zabawy - typ varint w języku takim jak C ++. Zbuduj go z
new
tablicy ints.Nie jest trudno wdrożyć dodawanie: po prostu x lub bajty razem i sprawdź wysokie bity: jeśli istnieje operacja przeniesienia,
new
w nowym górnym bajcie i przenieś bit. Odejmowanie następuje trywialnie w reprezentacji uzupełnienia 2. (Jest to również znane jako sumator przenoszenia tętnienia).Mnożenie następuje podobnie; użyj iteracyjnego dodawania / przesuwania. Jak zawsze prawdziwym zwrotem w twoim ogonie jest podział [*].
Co jednak straciłeś, kiedy to się stało?
Deterministyczny czas. Masz funkcję syscall (
new
), która może wyzwalać punkty, które niekoniecznie są kontrolowane.Przestrzeń deterministyczna.
Matematyka półprogramowa jest powolna.
Jeśli musisz używać języka warstwy sprzętowej, a także musisz działać na wysokim (wolnym) poziomie i nie chcesz osadzać silnika skryptowego,
varint
ma to sens. Prawdopodobnie jest gdzieś napisane.[*] Por. Algorytmy sprzętowe matematyki dla szybszych sposobów robienia tego - zwykle sztuczka polega na operacjach równoległych.
źródło
To dobre pytanie. Wyjaśnia, dlaczego język taki jak Python nie potrzebuje „krótkich, całkowitych, długich, bigintu itp.”: Liczby całkowite są, no cóż, liczbami całkowitymi (w Pythonie 3 jest jeden typ liczb całkowitych) i nie mają limitu wielkości (poza oczywiście pamięć komputera).
Jeśli chodzi o Unicode, kodowanie UTF-8 (które jest częścią Unicode) używa tylko jednego znaku dla znaków ASCII, więc nie jest tak źle.
Mówiąc bardziej ogólnie, dynamiczne języki wydają się iść w kierunku, o którym wspomniałeś. Jednak ze względu na wydajność bardziej ograniczone typy są przydatne w niektórych przypadkach (np. Programy, które muszą działać szybko). Nie widzę większych zmian w dającej się przewidzieć przyszłości, ponieważ procesory organizują dane w bajtach (lub 2, 4, 8 itd.).
źródło
Na podstawie teorii języka masz rację. Typy powinny opierać się na zestawie stanów prawnych, transformacjach dostępnych dla tych stanów oraz operacjach wykonywanych na tych stanach.
Jest to jednak mniej więcej to, co oferuje programowanie OOP w typowej formie. W rzeczywistości w Javie skutecznie rozmawiasz o klasach
BigInteger
iBigDecimal
, które przydzielają miejsce na podstawie tego, ile potrzeba do przechowywania obiektu. (Jak zauważył FrustratedWithFormsDesigner, wiele języków skryptowych jest jeszcze dalej na tej ścieżce i nawet nie wymaga deklaracji typu i będzie przechowywać wszystko, co im dasz).Wydajność jest jednak nadal istotna, a ponieważ zmiana typów w czasie wykonywania jest kosztowna, a ponieważ kompilatory nie mogą zagwarantować maksymalnego rozmiaru zmiennej w czasie kompilacji, nadal mamy zmienne o wielkości statycznej dla prostych typów w wielu językach.
źródło
int
lub adouble
, a jeśli nie, są tego świadomi, więc dynamiczne określanie wartości jest funkcją, za którą nie trzeba płacić.To zależy od języka. W przypadku języków wyższego poziomu, takich jak Python, Ruby, Erlang i takie, masz tylko pojęcie liczb całkowitych i dziesiętnych.
Jednak dla pewnej klasy języków takie typy są bardzo ważne. Kiedy piszesz kod do odczytu i zapisu formatów binarnych, takich jak PNG, JPeg itp., Musisz dokładnie wiedzieć, ile informacji jest odczytywanych jednocześnie. To samo z pisaniem jądra systemu operacyjnego i sterowników urządzeń. Nie wszyscy to robią, aw wyższych językach używają bibliotek C do szczegółowego ciężkiego podnoszenia.
W
short
dalszym ciągu jest miejsce na bardziej szczegółowe typy, ale wiele problemów programistycznych nie wymaga takiej precyzji.źródło
Niedawno utworzyłem edytor logiki drabinowej i środowisko wykonawcze i postanowiłem bardzo ograniczyć się do typów:
Uważam, że dzięki temu jest bardziej intuicyjny dla użytkownika. Jest to radykalne odejście od większości sterowników PLC, które mają cały „normalny” zakres typów, które można zobaczyć w języku takim jak C.
źródło
Języki programowania zmierzają w tym kierunku. Weźmy na przykład łańcuchy. W starych językach musisz zadeklarować rozmiar łańcucha, jak
PIC X(42)
w języku COBOL,DIM A$(42)
w niektórych wersjach języka BASIC lub [VAR
]CHAR(42)
w języku SQL. W nowoczesnych językach masz tylko jeden dynamicznie przydzielanystring
typ i nie musisz myśleć o rozmiarze.Liczby całkowite są jednak różne:
Spójrz na Python. Służył do rozróżniania liczb całkowitych
int
wielkości maszyny (long
) i liczb całkowitych o dowolnym rozmiarze ( ). W wersji 3.x tej pierwszej nie ma (staralong
jest nowaint
) i nikt jej nie przeoczy.Ale nadal istnieje wyspecjalizowany typ sekwencji 8-bitowych liczb całkowitych w postaci
bytes
ibytearray
. Dlaczego nie używaćtuple
lublist
liczb całkowitych, odpowiednio? To prawda,bytes
że ma dodatkowe metody łańcuchowe, któretuple
tego nie robią, ale z pewnością wydajność miała z tym wiele wspólnego.Nie całkiem. Podejście „wszystko ma podwójną precyzję” jest bardzo powszechne.
źródło
unum64 += ring32a-ring32b
zawsze zapewni poprawne zachowanie, niezależnie od tego, czy domyślny typ liczby całkowitej to 16 bitów czy 64 [zauważ, że użycie+=
jest kluczowe; wyrażenie takieunum64a = unum64b + (ring32a-ring32b);
powinno zostać odrzucone jako dwuznaczne.]Rozumiem rozumowanie, zmienne / obiekty są przechowywane w pamięci, pamięć musi zostać przydzielona i dlatego musimy wiedzieć, jak duża może być zmienna. Ale tak naprawdę, czy współczesny język programowania nie powinien być w stanie poradzić sobie z „typami adaptacyjnymi”, tzn. Jeśli coś jest kiedykolwiek przydzielane tylko w krótkim zakresie, wykorzystuje mniej bajtów, a jeśli coś jest nagle przydzielane, bardzo duża liczba, pamięć jest przydzielana odpowiednio dla tego konkretnego przypadku.
Float, real i double są nieco trudniejsze, ponieważ typ zależy od wymaganej precyzji. Ciągi powinny jednak być w stanie zajmować mniej pamięci w wielu przypadkach (w .Net), w których używa się głównie ascii, ale ciągih zawsze zajmują podwójną pamięć z powodu kodowania Unicode.
Fortran miał coś podobnego (nie wiem, czy dokładnie to masz na myśli, ponieważ naprawdę widzę dwa pytania). Na przykład, w F90 w górę, nie trzeba jawnie definiować rozmiaru typu , że tak powiem. Co jest dobre, nie tylko dlatego, że daje centralne miejsce do definiowania typów danych, ale także przenośny sposób ich definiowania. PRAWDZIWE * 4 nie jest takie samo we wszystkich implementacjach na wszystkich procesorach (a przez procesor mam na myśli procesor + kompilator), a nie przez długi czas.
selected_real_kind (p, r) zwraca wartość rodzaju prawdziwego typu danych z dokładnością dziesiętną większą niż co najmniej p cyfr i zakresem wykładnika większym co najmniej r.
Idź na przykład;
(Myślę, że jest to raczej oczywisty przykład).
Nadal nie wiem, czy poprawnie zrozumiałem twoje pytanie, i właśnie o tym myślisz.
źródło