Różnica między „warunkiem wstępnym” a „zapewnieniem” w szybkości?

105

Jaka jest różnica między precondition(condition: Bool, message: String)i assert(condition: Bool, message: String)w języku Swift?

Oba wyglądają dla mnie tak samo. W jakim kontekście powinniśmy używać jednego nad drugim?

Chao Ruan
źródło

Odpowiedzi:

125

assertsłuży do sprawdzania poczytalności podczas testowania, natomiast preconditionsłuży do ochrony przed rzeczami, które w przypadku ich wystąpienia oznaczałyby, że program nie mógłby po prostu działać.

Na przykład, możesz zastosować assertjakieś obliczenia, które dają rozsądne wyniki (powiedzmy w pewnych granicach), aby szybko sprawdzić, czy masz błąd. Ale nie chciałbyś tego wysyłać, ponieważ wynik poza zakresem może być prawidłowy i nie krytyczny, więc nie powinieneś zawieszać aplikacji (przypuśćmy, że używałeś go tylko do wyświetlania postępu na pasku postępu).

Z drugiej strony, sprawdzenie, czy indeks w tablicy jest prawidłowy podczas pobierania elementu, to precondition. Nie ma sensownej następnej akcji, jaką obiekt tablicy miałby podjąć, gdy zostanie poproszony o niepoprawny indeks, ponieważ musi zwrócić nie opcjonalną wartość.

Pełny tekst z dokumentów (spróbuj kliknąć opcję asserti preconditionXcode):

Warunek wstępny

Sprawdź warunek konieczny do postępu.

Użyj tej funkcji, aby wykryć warunki, które muszą uniemożliwić działanie programu nawet w kodzie wysyłkowym.

  • W placach zabaw i kompilacjach -Onone (wartość domyślna dla konfiguracji debugowania Xcode): jeśli conditionwartość ma wartość false, po wydrukowaniu zatrzymaj wykonywanie programu w stanie możliwym do debugowania message.

  • Kompilacje In -O (wartość domyślna dla konfiguracji wydania Xcode): jeśli conditionwartość ma wartość false, zatrzymaj wykonywanie programu.

  • W kompilacjach -Ounchecked conditionnie jest oceniany, ale optymalizator może założyć, że zostanie oszacowany true. Niespełnienie tego założenia w kompilacjach -Ounchecked jest poważnym błędem programistycznym.

Zapewniać

Tradycyjne potwierdzenie w stylu C z opcjonalną wiadomością.

Użyj tej funkcji do wewnętrznych kontroli poprawności, które są aktywne podczas testowania, ale nie wpływają na wydajność kodu wysyłkowego. Aby sprawdzić nieprawidłowe użycie w kompilacjach wydania; zobacz precondition.

  • W placach zabaw i kompilacjach -Onone (wartość domyślna dla konfiguracji debugowania Xcode): jeśli conditionwartość ma wartość false, po wydrukowaniu zatrzymaj wykonywanie programu w stanie możliwym do debugowania message.

  • Kompilacje In -O (domyślne dla konfiguracji wydania Xcode) conditionnie są oceniane i nie ma żadnych efektów.

  • W kompilacjach -Ounchecked conditionnie jest oceniany, ale optymalizator może założyć, że zostanie oszacowany true. Niespełnienie tego założenia w kompilacjach -Ounchecked jest poważnym błędem programistycznym.

Prędkość powietrza
źródło
2
„Ale nie chciałbyś wysyłać z tym, ponieważ wynik poza zakresem może być ważny i nie jest krytyczny, więc nie powinieneś zawieszać aplikacji”, to jest dla mnie bardzo niejasne. Czy możesz podać dokładny przykład? Może jakiś kod.
Honey
2
Odpowiadając na twoje pytanie, osobiście używam potwierdzeń, aby wychwycić rzeczy, które po prostu nie powinny się zdarzyć w mojej kompilacji, gdy ją piszę i testuję. Wyobraź sobie instrukcję strażnika odczytującą JSON tam, gdzie data["name"]nie istnieje, a powinna. Posiadanie asertu wewnątrz strażnika ... else {} pomogłoby mi złapać mój błąd przez awarię i doprowadzenie mnie do problemu. Podobnie, gdyby ten kod był w produkcji, assert nie spowodowałby awarii programu, a return nilkażdy kod zapasowy, którego użyłem ( ), by go przejął.
Alec O
1
Nie powinieneś sprawdzić indeksu i nic nie robić, zamiast zepsuć całą aplikację?
Iulian Onofrei
Tak, powinieneś sprawdzić indeks, ale czasami wszyscy wpadają w błąd, a użycie potwierdzeń pomaga ci uświadomić sobie, że powinieneś był sprawdzić indeks, gdy zapomniałeś.
Victor Engel,
„Ale nie chciałbyś wysyłać z tym, ponieważ wynik poza zakresem może być prawidłowy i nie krytyczny, więc nie powinien zawieszać aplikacji”. Możesz wysłać swoją aplikację z dowolną liczbą potwierdzeń. Swift po prostu nie oceni twoich warunków w bloku asercji w aplikacji do wydania
Akshansh Thakur
90

Zauważyłem, że pomocny jest program Swift Asserts - brakująca instrukcja

                        debug   release   release
function                -Onone  -O       -Ounchecked
assert()                YES     NO        NO
assertionFailure()      YES     NO        NO**
precondition()          YES     YES       NO
preconditionFailure()   YES     YES       YES**
fatalError()*           YES     YES       YES

Oraz z ciekawych dyskusji na temat Swift Evolution

- assert: sprawdzanie własnego kodu pod kątem błędów wewnętrznych

- warunek wstępny: sprawdzenie, czy Twoi klienci podali Ci prawidłowe argumenty.

Musisz także uważać na to, czego użyć, zobacz assertionFailure i Optimization Level

onmyway133
źródło
Czy możesz wyjaśnić różnicę między własnym kodem a klientem? Co do klienta, czy masz na myśli wstawianie liczb tam, gdzie oczekuje się ciągu znaków? Czy nie należy tego traktować za pomocą prostej obsługi błędów?
Honey
@ Kochanie, myślę, że ma na myśli argumenty / wyniki wywołań sieciowych API lub własne wtyczki klienta.
Chen Li Yong
Klientem byłaby osoba używająca twojego kodu, powiedzmy, że piszesz bibliotekę, a programista przekazuje nieprawidłowe dane. Nie chciałbyś z wdziękiem kontynuować, ponieważ można to uznać za poważny błąd programistyczny. Prawdopodobnie nigdy nie powinieneś zawieszać się przy nieprawidłowych danych API sieci, ponieważ jest to bardzo nieprzydatne dla użytkownika.
bompf,
@ onmyway133: Z Xcode krótką pomoc, myślę, precondition()i preconditionFailure()o tych samych zachowań . Różnica między tymi funkcjami jest taka: preconditionpotrzebujesz warunku w środku, a preconditionFailurepo prostu wyrzuć.
nahung89
12

preconditionJest aktywny w trybie zwolnienia Więc kiedy wysyłamy swoją aplikację, a warunek udało aplikacja zakończy. Assertdziała domyślnie tylko w trybie debugowania.

Znalazłem świetne wyjaśnienie, kiedy używać go na NSHipster:

Twierdzenia są pojęciem zapożyczonym z logiki klasycznej. W logice twierdzenia są twierdzeniami o zdaniach w ramach dowodu. W programowaniu asercje oznaczają założenia, które programista poczynił na temat aplikacji w miejscu, w którym zostały zadeklarowane.

Gdy są używane jako warunki wstępne i warunki końcowe, które opisują oczekiwania dotyczące stanu kodu na początku i na końcu wykonania metody lub funkcji, asercje tworzą kontrakt. Asercji można również używać do wymuszania warunków w czasie wykonywania, aby zapobiec wykonaniu, gdy pewne warunki wstępne zawiodą.

Greg
źródło
Asercje można włączać i wyłączać za pomocą flagi kompilatora; mogą być aktywne w wysłanym kodzie.
Pétur Ingi Egilsson
6

warunek wstępny

func precondition(condition: @autoclosure () -> Bool, _ message: @autoclosure () -> String = default, file: StaticString = default, line: UWord = default)

Sprawdź warunek konieczny do postępu.

  1. Użyj tej funkcji, aby wykryć warunki, które muszą uniemożliwić działanie programu nawet w kodzie wysyłkowym.
  2. W placach zabaw i kompilacjach -Onone (domyślne dla konfiguracji debugowania Xcode): jeśli warunek ma wartość false, po wydrukowaniu komunikatu zatrzymaj wykonywanie programu w stanie możliwym do debugowania.
  3. Kompilacje In -O (domyślne dla konfiguracji Release Xcode): jeśli warunek ma wartość false, zatrzymaj wykonywanie programu.
  4. W kompilacjach -Ounchecked warunek nie jest oceniany, ale optymalizator może założyć, że uzyskałby wartość true. Niespełnienie tego założenia w kompilacjach -Ounchecked jest poważnym błędem programistycznym.

zapewniać

func assert(condition: @autoclosure () -> Bool, _ message: @autoclosure () -> String = default, file: StaticString = default, line: UWord = default)

Tradycyjne potwierdzenie w stylu C z opcjonalną wiadomością.

  1. Użyj tej funkcji do wewnętrznych kontroli poprawności, które są aktywne podczas testowania, ale nie wpływają na wydajność kodu wysyłkowego. Aby sprawdzić nieprawidłowe użycie w kompilacjach wydania; patrz warunek wstępny.

  2. W placach zabaw i kompilacjach -Onone (domyślne dla konfiguracji debugowania Xcode): jeśli warunek ma wartość false, po wydrukowaniu komunikatu zatrzymaj wykonywanie programu w stanie możliwym do debugowania.

  3. W kompilacjach -O (wartość domyślna dla konfiguracji wydania Xcode) warunek nie jest oceniany i nie ma żadnych efektów
  4. W kompilacjach -Ounchecked warunek nie jest oceniany, ale optymalizator może założyć, że uzyskałby wartość true. Niespełnienie tego założenia w kompilacjach -Ounchecked jest poważnym błędem programistycznym
13th Ghost
źródło
0

Chciałem tylko dodać moje 2 centy. Możesz dodać dowolną liczbę potwierdzeń w swoim kodzie, ile chcesz. Możesz wysłać swój kod z tymi potwierdzeniami. Swift NIE ocenia tych bloków kodu dla aplikacji produkcyjnych. Są one oceniane tylko w przypadku trybu debugowania.

Dodanie linku do dokumentacji

Załączam również obraz ze swift.org

wprowadź opis obrazu tutaj

Należy również zauważyć, że nie dotyczy to warunków wstępnych. Kod wysłany z warunkami wstępnymi ulegnie awarii, a aplikacja zostanie zamknięta, jeśli warunki wstępne nie zostaną ocenione jako prawdziwe.

Krótko mówiąc, asercje służą do debugowania, ale mogą być wysyłane bez wpływu na produkcję. Asercje będą oceniane w trybie debugowania, ale nie w środowisku produkcyjnym.

I

Warunki wstępne służą do zapobiegania nieoczekiwanym rzeczom w środowisku produkcyjnym. Te warunki są oceniane i spowodują zamknięcie aplikacji w przypadku, gdy zostaną ocenione jako fałszywe

Akshansh Thakur
źródło