Dlaczego Swift nie wymaga średników? [Zamknięte]

20

Zwykle piszę w języku C # lub Objective-C, a ostatnio postanowiłem nauczyć się nowego języka programowania Apple - Swift.

Pierwszą rzeczą, którą zauważyłem, jest to, że nie trzeba dodawać średników, aby zakończyć linię w Swift, ale jeśli zrobisz to - przynajmniej z tego, co przetestowałem - nie będzie to kolidowało z kompilatorem.

Kiedy piszę:

int someNumber = 0;

w Celu C średnik mówi programowi, że linia się skończyła i nie przechodzi do następnej linii.

Za pomocą Swift mogę zadeklarować zmienną za pomocą

var someNumber:Int = 5

i nie dodaje średnika, a system wie, że to koniec linii.

Co pozwala niektórym językom to robić, a innym nie? Dlaczego nie zachować jednolitego systemu dodawania średnika na końcu?

Memj
źródło
Nie wszyscy pochodzą z innych języków, więc skąd mieliby wiedzieć, że nie są jednolici? Czy Apple nie przyciągnie więcej nowych programistów dzięki Swift, pozbywając się części Objective-C, których nie lubi wiele osób?
JeffO,
2
Wielu weterynarzy Obj-C jest niezadowolonych z Swift i zdecydowanie woli Obj-C. Można to zobaczyć na forach Apple. Swift pojawił się dopiero w 2014 roku i jeśli PEŁNE błędy i zmiany są wprowadzane co kilka miesięcy w języku, a Swift2.0 pojawi się tej jesieni. Swift jest oparty na Obj-C, ale jego celem jest ułatwienie nauki kodowania za pomocą bardziej prostego języka angielskiego.
Memj
Stare implementatory kompilatora były po prostu leniwe i / lub musiały być bardziej wydajne dzięki prostszemu analizowaniu. Nie ma już takiej potrzeby. Jest to to samo, co wnioskowanie o typach lokalnych, nie masz go tylko wtedy, gdy autor kompilatora jest leniwy i nie dba o doświadczenie programistów.
Ebuall

Odpowiedzi:

18

Co pozwala niektórym językom to robić, a innym nie? Dlaczego nie zachować jednolitego systemu dodawania średnika na końcu?

Robert udzielił dobrej odpowiedzi na temat Swift, postaram się dodać trochę więcej o parsowaniu w ogóle i dlaczego używać lub nie średników.

Podczas kompilacji programu, zanim plik źródłowy zostanie przekształcony w kod wykonywalny, należy wykonać kilka kroków, z których jednym z pierwszych jest czytanie i parsowanie . Podczas parsowania kod jest przekształcany z sekwencji znaków w ustrukturyzowaną reprezentację zgodnie z gramatyką języka. W tym celu konieczne jest, aby elementy, które składają się na Twój kod (zmienne, stałe, deklaracje itp.) Zostały w jakiś sposób zidentyfikowane i rozdzielone. Kiedy składasz deklarację:

int someNumber = 0;

To tylko sekwencja znaków, którą należy jakoś przekształcić w koncepcję „stwórz„ rzecz ”o nazwie someNumbertypu inti przypisaj 0do niej” .

Wymaga to określenia, gdzie dokładnie zaczyna się i kończy instrukcja. Wyobraź sobie, że masz to:

int someNumber = 0;
int otherNumber = 1;

Musisz wiedzieć, że są to dwie różne deklaracje. ;W językach C-jak jest wykorzystywana do tego, więc parser odczytuje znaki dopóki nie znajdzie, i próbuje zrozumieć, co właśnie czytać jako pojedynczej instrukcji. Pozwala to, jak powiedział Robert, mieć kilka instrukcji w tej samej linii, takich jak:

int someNumber = 0; int otherNumber = 1;

Który ma dokładnie taki sam efekt jak pisanie ich w dwóch wierszach.

W innych językach, takich jak Python , należy umieścić każdą instrukcję w innym wierszu.

x = 3
if x < 10:
   print 'x smaller than 10'
else:
   print 'x is bigger than 10 or equal'

Nie ma więc potrzeby dodawania a ;, ponieważ sam język uniemożliwia dodawanie instrukcji w tym samym wierszu!

Jednak inne języki, takie jak LISP lub Scheme , mają zupełnie inny sposób grupowania instrukcji (ok, to nie są naprawdę instrukcje, ale na razie zignorujmy to). Masz więc nawias na wszystko:

(define (do-stuff x)
  (begin
    (display (format "value: ~a" x))
    x))

Znowu, nie trzeba ;tylko dlatego, że korzystają z tych samych symboli ( ), () do rzeczy, które są w innych językach {, }, :, itd. Ktoś, kto tylko zna składni Lisp może zapytać: Dlaczego trzeba ;na koniec swojego sprawozdania ?

Wystarczy dodać dziwniejszy przykład: OCaml ma nie tylko średnik na końcu instrukcji ... ma dwa!

let rec fact x =
    if x <= 1 then 1 else x * fact (x - 1);;

Dlaczego? Nie wiem :)

Różne języki zostały zaprojektowane z różnymi celami i różnymi filozofiami. Jeśli wszystkie języki mają tę samą składnię i konwencje, zapewne pozwolą ci robić to samo w ten sam sposób.

Sebastian
źródło
4
Dobre zdanie końcowe.
Thomas Eding,
Ładne przykłady, ale nie odpowiedziałeś na pytanie.
Robo Robok,
Dodatkowy punkt danych: Niektóre języki mają coś w rodzaju odwrotnego podejścia do rodziny w stylu C: Np. HyperTalk używa podziałów linii jako twardego końca linii (zamiast średników) i wymaga ucieczkowych podziałów linii, jeśli chcesz kontynuować instrukcję w kilku liniach. Co zabawne, własny preprocesor C również działa w ten sposób.
uliwitness
11

Podziały linii są używane zamiast średników w celu ograniczenia końca instrukcji.

W przewodniku językowym: Podstawy mówi:

W przeciwieństwie do wielu innych języków, Swift nie wymaga wpisywania średnika (;) po każdej instrukcji w kodzie, chociaż możesz to zrobić, jeśli chcesz. Średniki są jednak wymagane, jeśli chcesz napisać wiele oddzielnych instrukcji w jednym wierszu.

Dlaczego? Ponieważ tak chcieli projektanci języków.

Drugie zdanie powyżej wskazuje, dlaczego nie potrzebujesz średników; większość instrukcji ma jedną linię. Obserwuj ten przykład sortowania bąbelkowego; kombinacja instrukcji jednowierszowych i bez średników zapewnia bardzo czystą składnię podobną do VB, ale mniej szczegółową:

func bubbleSort<T:Comparable>(inout list:[T]) {
    var done = false
    while !done {
        done = true
        for i in 1..<list.count {
            if list[i - 1] > list[i] {
                (list[i], list[i - 1]) = (list[i - 1], list[i])
                done = false
            }
        }
    }
}

Ponieważ instrukcje w Swift zwykle kończą się podziałem wiersza, potrzeba użycia średników do oznaczenia końca instrukcji jest zmniejszona. Inne języki używające średników nie działają w ten sposób; możesz swobodnie pisać wieloliniowe instrukcje, ale kompilator wie tylko, że instrukcja się zakończyła, gdy umieścisz średnik na jej końcu.

Gdy instrukcje nie kończą się na podziale wiersza, musisz umieścić podział wiersza w miejscu, które kompilator Swift może rozpoznać jako kontynuację poprzedniego wiersza:

let s2 = str
        .lowercaseString
        .replace("hello", withString: "goodbye")
Robert Harvey
źródło
2
Ostatnie zdanie jest fałszywe, nie ma określonej lokalizacji, w której można wstawić podziały linii. Dobrze jest zachować wcięcia i wyrównanie linii kodu, aby poprawić czytelność.
Eneko Alonso,
Ciekawostka: ma to wpływ na zgłaszanie błędów. Wiele kompilatorów C (clang jest w tym szczególnie dobry) używa średników do znalezienia końca instrukcji z błędem składni i może wykorzystać te informacje do np. Zgłaszania brakujących nawiasów zamykających bliżej miejsca, w którym faktycznie ich brakuje. Brak średników, błąd w Swift może często powodować zawężenie poniższej linii do jej zawierającego błędy poprzednika i doprowadzić do naprawdę dziwnych komunikatów o błędach.
uliwitness