Zasada KISS zastosowana do projektowania języka programowania?


14

KISS („zachowaj to proste, głupie” lub „utrzymaj to proste głupie”, patrz np. Tutaj ) jest ważną zasadą w tworzeniu oprogramowania, nawet jeśli najwyraźniej wywodzi się z inżynierii. Cytowanie z artykułu w Wikipedii:

Najlepszym przykładem tej zasady jest historia, w której Johnson przekazał zespołowi inżynierów garść narzędzi, z wyzwaniem, że projektowany przez nich samolot odrzutowy musi być naprawiany przez przeciętnego mechanika w terenie w warunkach bojowych przy użyciu tylko tych narzędzi. Stąd „głupi” odnosi się do związku między sposobem, w jaki rzeczy się psują, a zaawansowaniem dostępnym do ich naprawy.

Gdybym chciał zastosować to w dziedzinie tworzenia oprogramowania, zastąpiłbym „odrzutowce” na „oprogramowanie”, „przeciętnego mechanika” na „przeciętnego programistę” i „w warunkach bojowych” na „w ramach oczekiwanego rozwoju / utrzymania oprogramowania warunki ”(terminy, ograniczenia czasowe, spotkania / przerwy, dostępne narzędzia itd.).

Jest więc powszechnie akceptowanym pomysłem, że należy starać się, aby program był prosty (lub głupi , jeśli pominiesz przecinek), aby łatwo później nad nim popracować.

Ale czy zasadę KISS można zastosować także do projektowania języka programowania? Czy znasz jakieś języki programowania, które zostały zaprojektowane specjalnie z myślą o tej zasadzie, tj. „Pozwalają przeciętnemu programistowi w przeciętnych warunkach pracy pisać i utrzymywać jak najwięcej kodu przy minimalnym wysiłku poznawczym”?

Jeśli cytujesz jakiś konkretny język, byłoby dobrze, gdybyś mógł dodać link do jakiegoś dokumentu, w którym projektanci wyraźnie wyrażają ten zamiar. W każdym razie chciałbym dowiedzieć się o (udokumentowanych) intencjach projektantów niż o twoich osobistych opiniach na temat określonego języka programowania.


4
Czy zapoznałeś się z podstawową rodziną języków (a przynajmniej oryginalną intencją za nimi)?

4
BASIC i Pascal ... oba zaprojektowane jako języki instruktażowe.
Michael Brown,

1
Co rozumiesz przez „prosty”? Większość języków jest dość prosta, ponieważ nie ma ich wiele. Nic nie było mniej skomplikowane niż asembler. Szkielety są często skomplikowane, ale zostały zaprojektowane tak, aby umożliwić „pisanie i utrzymywanie jak największej ilości kodu przy jak najmniejszym wysiłku poznawczym”.
pdr

7
Schemat (r) był używany jako język nauczania przez lata (dekady?) I został opracowany przez uproszczenie LISP i Algola (i może być więcej). Książka SICP zajmuje znacznie mniej czasu na naukę samego języka. Do głowy przychodzą również DSL.
vpit3833,

3
@Giorgio spójrz na Haskell. Ma bardzo i mam na myśli bardzo mało wbudowanych bitów. Większość operatorów to funkcje, które znajdują się w głównej bibliotece, ale nie są konieczne dla samego języka, dołożył wszelkich starań, aby usunąć wszystkie niepotrzebne elementy
Jimmy Hoffa

Odpowiedzi:


15

Kiedy myślę o minimalizmie, myślę o Lisp i Go . W Lisp masz tylko funkcje i listy, które są tak proste, jak tylko możesz (cóż, jest ich trochę więcej, ale cokolwiek). Myślę jednak, że sprawa Go jest bardziej interesująca.

Go został zaprojektowany tak, aby był prosty (jest to przyzwoity odczyt). Termin, którego używają, to „ortogonalność funkcji”, co oznacza, że ​​każda funkcja powinna być dodana tylko wtedy, gdy zapewnia coś naprawdę wyjątkowego. Wydaje się, że wynika to z zaangażowania autorów ( przychodzą mi na myśl Russ Cox i Rob Pike ) z Plan9 , który był prostą wersją systemu UNIX. (Jeśli interesuje Cię minimalistyczny design, dobrze jest przeczytać artykuł Roba Pike'a na temat prostego systemu okienkowego .)

Oto kilka prostych przykładów składni:

Tylko jedna konstrukcja pętli

Pętla może wyglądać następująco:

Nieskończona pętla

for {
}

Podczas pętli

for <conditional> {
}

Tradycyjny dla pętli

for i := 0; i < 10; i++ {
}

Foreach loop

// works for maps or arrays
for k, v := range arr {
}

Przełącznik wielofunkcyjny

switch {
    // cases must be evaluate to a boolean
}

switch <value> {
}

switch t := <value>; t {
    // can use t inside
}

Wielokrotny zwrot

return val1, val2, ...
  • Usuwa potrzebę rzucania (błąd należy podać jako ostatnią zwracaną wartość)
  • Eliminuje potrzebę używania parametrów
  • Usuwa potrzebę krotek

Interfejsy

type X interface {
    DoSomething()
    String() string
}
  • Rozwiązuje podobne problemy jak leki generyczne
  • Pozwala na abstrakcję

Osadzanie

type A struct {
    Thing string
}

type B struct {
    A // embeds A in B, so B.Thing refers to A.Thing
}
  • Rozwiązuje ten sam problem co dziedziczenie
  • Eliminuje potrzebę zajęć

Kanały

Może być stosowany do implementacji semaforów

var c = make(chan bool, 1)
c<-true // semaphore lock
<-c // semaphore free

Służy do przekazywania wiadomości między wątkami

func produce(c chan<- bool) {
    for {
        c <- true
    }
}
func consume(c <-chan bool) {
    for {
        <-c
    }
}

var c = make(chan bool)
go produce(c)
go consume(c)

Może być używany do obsługi zdarzeń asynchronicznych

func async() chan bool {
    var c = make(chan bool)
    go doSomethingAsync(c)
    return c
}

// wait for long async process to finish
c := async()
select {
    case _ = <-c:
}

Wniosek

Nie będę wchodził w każdą część składni, ale mam nadzieję, że zobaczysz, co potrafi minimalizm. Język jest intrygujący nie dlatego, że dodaje mnóstwo nowych funkcji, ale dlatego, że wykorzystuje najlepsze funkcje z innych języków bez żadnych dodatkowych elementów.

Zazwyczaj istnieje jeden „najlepszy” sposób rozwiązania problemu. Na przykład na liście mailingowej wielu użytkowników skarży się na brak generycznych. Po dyskusji zdają sobie sprawę, że wszystko, co chcą zrobić, można zrobić za pomocą interfejsów. Przeczytaj o skutecznym przejściu na przykłady składni idiomatycznej.

Zaletą języków KISS jest możliwość pisania kodu idiomatycznego, ponieważ styl kodu jest ograniczony przez język. Na przykład w Go nie można napisać czegoś takiego:

if <condition>
    statement;

Musisz użyć nawiasów klamrowych:

if <condition> {
    statement;
}

Istnieje wiele innych przykładów tego w składni, co ułatwia czytanie kodu innych osób.

Zalety języka KISS w porównaniu z atrakcyjnymi językami:

  • łatwiej zrozumieć kod innych
  • łatwiejsza obsługa całego języka (C ++ jest znany z tego, że jest trudny do zrozumienia)
  • skup się na algorytmie, a nie na składni

5
Moim skromnym zdaniem składnia tradycyjnej pętli for nie jest taka, że ​​KISS. Oczywiście jest to znane każdemu programistowi podobnemu do C, ale pamiętam, kiedy po raz pierwszy się tego nauczyłem: byłem bardzo zdezorientowany. BASIC jest bardziej KISS: for i=1 to 10lub python:for item in group
mouviciel

3
@mouviciel - rzadko używam tradycyjnej pętli for. Problem for i = 1 to 10polega na tym, czy ikiedykolwiek będzie 10. Może to zależeć od języka (bash zawiera 10, python nie). Tradycyjna pętla for jest uniwersalna.
beatgammit

+1, szczególnie w przypadku podsumowania korzyści płynących z minimalizmu.
Giorgio

1
Idź, ponieważ studium przypadku jest interesujące, ponieważ jego przeciwnicy nie uważają go za język KISS. W rzeczywistości argument jest następujący: „prosty” język nie prowadzi do „prostego” kodu ani łatwiejszego zrozumienia. Czasami musi być bardziej złożona (powiedzmy, dobra obsługa generycznych), aby kod był łatwiejszy do zrozumienia.
Andres F.,

14

Myślę, że Zen Pythona powie, dlaczego Python jest prostym językiem o wiele lepszym niż mogę:

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Edytuj w odpowiedzi na @Giorgio

Jak mówi twoje pytanie,

„Czy znasz języki programowania, które zostały zaprojektowane specjalnie z myślą o tej zasadzie, tj.„ Pozwalają przeciętnemu programistowi w przeciętnych warunkach pracy pisać i utrzymywać jak najwięcej kodu przy jak najmniejszym wysiłku poznawczym ””

Python jest dla mnie tym, co natychmiast przychodzi mi na myśl. Projekt Pythona jest bezpośrednią odpowiedzią na metodologię Perla, słynnego „Jest więcej niż jeden sposób na to”. To wspaniałe, ponieważ pozwala programistom bardzo łatwo pisać kod, ale nie pomaga w utrzymaniu. Po tym, jak wcześniej zarządziłem (bardzo słabo napisany) program napisany w Perlu, doceniam Python zmuszający zarówno dobre praktyki kodowania, jak i zwięzły język do gardła.

Python również nie zmusza cię do przestrzegania jednej określonej metodologii podczas pisania programów. Mogę zdecydować się na ścisły styl programowania obiektowego lub napisać prosty skrypt do wykonania sekwencyjnego. Nie trzeba inicjować klasy, a następnie wywołać main()metodę tak, jak w Javie, trzeba to zrobić. (Również drukowanie w standardzie Python jest wspaniałe, ale jest to raczej punkt zerowy).

Wreszcie, metodologia „Dołączone baterie” polegająca na włączeniu ekspansywnej standardowej biblioteki z językiem jest cudowna. Zamiast przeszukiwać zewnętrzne repozytorium pakietów, większość tego, czego potrzebuję, jest już zawarta w języku. Fajnie jest też mieć zewnętrzne repozytorium, ale nie trzeba go przekopywać, aby wykonać podstawową operację.


3
Dzięki za przydatne cytowanie. Czy jest to oficjalna intencja projektanta (ów) Pythona? Zauważ też, że nie wszyscy czytelnicy mogą zgodzić się z twoją opinią na temat Pythona, więc być może jest zbyt mocne stwierdzenie, że „Python jest prostym językiem” jako dobrze znany i zaakceptowany fakt. Czy byłoby możliwe sformułowanie go jako „Python został zaprojektowany z myślą o prostocie”?
Giorgio

@Giorgio - Doświadczenie wielu programistów na całym świecie sprawia, że ​​Python jest prostym językiem. Prosty do nauki, prosty do napisania i prosty do odczytania. Jeśli chodzi o cytat, ponieważ python jest „baterią w zestawie”, możesz uzyskać go bezpośrednio z języka za pomocą import thispolecenia.
mouviciel

1
TCL jest również dobrą odpowiedzią na to pytanie, a IIRC było również odpowiedzią na złożoność PERL.
jk.

@mouviciel Po tym, jak natknąłem się na niesamowicie skomplikowany kod spaghetti Pythona w wielu miejscach, nie sądzę, że Python osiąga tutaj swoje cele. Python nie jest lepszy od większości języków, jeśli chodzi o prostotę - może być bardzo dobry w przypadkowym zaciemnieniu.
Izkata

1
Python jest prosty, o ile ludzie trzymają się z dala od większości __magic_functions __ () i @decorators.
weberc2

3

Głównym kluczem do utrzymania „prostoty” jest rozpoznanie, kiedy złożoność będzie konieczna, i posiadanie części systemu, które najlepiej sobie z tym poradzą, zrobią to. Posiadanie jednego rodzaju odniesienia do obiektu, który nie czyni rozróżnienia między niezmiennymi wartościami, zmiennymi wartościami i bytami, sprawia, że ​​Java jest „prosta”, nie eliminuje potrzeby rozróżniania wartości od bytów; po prostu pozbawia programistów narzędzi, które mogą im w tym pomóc.

Mówiąc bardziej ogólnie, jeśli ktoś chce, aby język programowania lub funkcja obsługiwały wiele przypadków użycia, należy upewnić się, że nie będzie żadnych sytuacji, w których różne zachowania byłyby odpowiednie w różnych przypadkach użycia, ale kompilator nie byłby w stanie stwierdzić je osobno. Dodanie większej liczby typów do języka lub frameworka może wydawać się komplikacją, ale w wielu przypadkach może faktycznie ułatwić.

Rozważmy na przykład bałagan reguł otaczających typy podpisane i niepodpisane w C. Złożoność tych reguł wynika z faktu, że niektóre kody używają niepodpisanych typów liczb całkowitych do reprezentowania liczb, podczas gdy inny kod używa ich do reprezentowania członków zawijanego pierścienia algebraicznego (konkretnie, zestaw liczb całkowitych przystających mod 2ⁿ). Reguły konwersji typów zachowują się w sposób, który czasem jest odpowiedni dla jednego użycia, a czasem w sposób odpowiedni dla drugiego. Posiadanie osobnych typów zawijania i nie zawijania podwoiłoby liczbę typów całkowitych, ale mogłoby uprościć związane z nimi reguły:

  • Dowolny nie będący liczbą całkowitą typ dowolnego rozmiaru może być przypisany do pierścienia o dowolnym rozmiarze; pierścień można przypisać tylko do pierścienia o równym lub mniejszym rozmiarze.

  • Operacje inne niż operatory relacyjne, obejmujące niecałkowitą liczbę całkowitą i pierścień, pośrednio przekonwertują liczbę całkowitą na typ pierścienia.

  • Pierścienie mogą być jednoznacznie rzutowane na liczby lub na większe pierścienie; wartość niepodpisanego pierścienia jest najmniejszą nieujemną liczbą całkowitą, która po dodaniu do zera pierścienia dałaby wartość pierścienia. Wartość podpisanego pierścienia jest liczbą całkowitą najmniejszej wielkości, która po dodaniu do zera pierścienia dałaby wartość pierścienia, przy czym wartość ujemna jest preferowana w przypadku remisu.

  • Poza wymienionymi powyżej, pierścienie są ograniczone do operacji z pierścieniami tego samego rozmiaru lub mniejszymi.

  • Operacje na liczbach całkowitych innych niż pierścieniowe różnych typów powinny wyodrębnić liczby do typu, który może pomieścić wszystkie wartości dowolnego argumentu, lub powinien zostać odrzucony przez kompilator, jeśli nie istnieje odpowiedni typ

Zdefiniowanie typów pierścieni wydaje się podwoić liczbę typów całkowitych, ale znacznie uprościłoby pisanie przenośnego kodu. Używanie tego samego typu bez znaku dla liczb i dzwonków zmniejsza liczbę typów, ale prowadzi do skomplikowanych reguł, które praktycznie uniemożliwiają napisanie wydajnego przenośnego kodu.


+1 W pełni uzgodnione. „Prosty” język (prosty w znaczeniu posiadania małej specyfikacji) niekoniecznie prowadzi do prostego kodu lub łatwości rozumowania dla programisty.
Andres F.,

Świetny komentarz. Zwiększenie złożoności należy rozpatrywać pod kątem kosztów i korzyści.
user1071847,

2

Prawdopodobnie Tcl został opracowany zgodnie z tymi wytycznymi. Cały język można opisać tylko w 12 regułach na jednej stronie podręcznika . Jest niezwykle prosty i spójny.

Twórca Tcl twierdził, że jako pierwotne cele:

  • Język musi być rozszerzalny: każdej aplikacji musi być bardzo łatwo dodać własne funkcje do podstawowych funkcji języka, a funkcje specyficzne dla aplikacji powinny wyglądać naturalnie, tak jakby były zaprojektowane od samego początku w języku.
  • Język musi być bardzo prosty i ogólny, aby mógł łatwo współpracować z wieloma różnymi aplikacjami i aby nie ograniczał funkcji udostępnianych przez aplikacje.
  • Ponieważ większość interesujących funkcji będzie pochodzić z aplikacji, głównym celem języka jest integracja lub „sklejenie” rozszerzeń. Dlatego język musi mieć dobre możliwości integracji.

Z „ Historii Tcl ” - http://www.tcl.tk/about/history.html


2

Jeśli język jest poprawiony w projekcie z powodu KISS, nie może się rozwijać. Język, który nie może rosnąć, umrze.

W poniższym wideo Guy Steele sprytnie wyjaśnia, że ​​język programowania musi się rozwijać i dlaczego. Jeśli zastosujesz KISS, to w jaki sposób język może rosnąć, ponieważ po zwolnieniu jego zestaw narzędzi jest naprawiony i nigdy nie może się zmieniać.

Keynote Guya Steele'a na konferencji ACM OOPSLA w 1998 r. Na temat „Growing a Language” omawia znaczenie i problemy związane z projektowaniem języka programowania, który może być rozwijany przez jego użytkowników.

To godzinne wideo, ale warte obejrzenia. Jeśli nie wiesz, kim jest Guy Steele, naprawdę powinieneś mówić o projektowaniu języka.

Wybrałem ten film jako odpowiedź, ponieważ uważam, że zastosowanie KISS do projektowania języka jest w ogóle złe i mam nadzieję, że zobaczenie przemówienia znanej osoby zajmującej się projektowaniem języka pomoże poszerzyć twoje zrozumienie przyszłości projektowania języka.

Ponieważ przyszedłeś tutaj, aby dowiedzieć się o projektowaniu języka, a ja dałem ci powód, aby nie korzystać z KISS, to sprawiedliwe, że wskazałem coś, co znajduję w pomocy w projektowaniu języka. Wymiary poznawcze notacji

EDYTOWAĆ

Kiedy napisałem powyższą odpowiedź, była ona oparta na rozumowaniu: jeśli silnik może być obsługiwany tylko za pomocą stałego zestawu narzędzi, to moje przeformułowanie tego znaczenia w odniesieniu do projektu języka jest takie, że język nie może się zmienić po wydaniu. Komentarze wskazują, że nie o to chodziło. Pozwólcie, że przedstawię tę zmodyfikowaną odpowiedź, która będzie bardziej zgodna ze zmienionym zrozumieniem.

Jeśli przyjrzymy się wymiarom poznawczym notacji, to dowiadujemy się, że istnieje wiele konkurencyjnych wymiarów związanych z projektowaniem języka, a nie tylko prostota, a jeśli zbyt mocno skoncentrujesz się na jednym, cierpisz w innych. Z pytaniem, skupia się w dużej mierze na prostotę (KISS) Dobra, a wspierane przez znanego ludu projektu językowego, I przedstawiła mowę przez Guy Steele , aby pokazać, że stara się utrzymać wyłącznie prosty projekt wpłynie na inne wymiary. Co ważniejsze, staram się przekazać, że trzeba spojrzeć na wiele wymiarów i zważyć ich zalety i wady, a nie tylko prostotę.


3
Co się stanie, jeśli wideo stanie się niedostępne? Lub jeśli nie jest dostępny w niektórych krajach? Twoja odpowiedź powinna być kompletna i samodzielna, zaktualizuj ją, aby zawierała przynajmniej krótkie podsumowanie filmu, odpowiedzi zawierające tylko linki nie są naprawdę pomocne i mogą zostać usunięte w dowolnym momencie.
yannis,

3
@AndreasScheinert Przewodnik po odpowiedziach wyjaśnia, że ​​linkom zawsze muszą towarzyszyć streszczenia i / lub odpowiednie cytaty.
Thomas Owens

3
Nie jestem pewien, czy mogę zgodzić się z twoją oceną. Na przykład Tcl jest niezwykle prosty. Trwało to przez lata, z tylko 11 zasadami rządzącymi jego użyciem. Mimo to, choć jest to tak proste, urósł znacznie w ciągu ponad 20 lat swojego istnienia. Obecnie ma 12 zasad, co dowodzi, że biblioteka nie tylko powiększyła bibliotekę, ale także jej fundamentalny charakter pozwolił na wzrost, zachowując jednocześnie całą swoją prostotę.
Bryan Oakley,

1
„Jeśli zastosujesz KISS, to w jaki sposób język może rosnąć, ponieważ po wydaniu jego zestaw narzędzi jest naprawiony i nigdy nie może się zmieniać.”: Zależy to, co rozumiesz przez proste i rosnące. Czy masz na myśli dodawanie nowych bibliotek (w języku angielskim, dodawanie nowych słów do słownika) lub dodawanie nowych konstrukcji językowych (w języku angielskim oznaczałoby to dodanie np. Nowych czasów czasowników, nowych przyimków itd.). Języki naturalne ostatecznie przestają dodawać nowe reguły gramatyczne, podczas gdy dodają nowe słowa. Według mojej intuicji, proste odnosi się do liczby reguł gramatycznych, a nie do liczby bibliotek / słów.
Giorgio,

3
@Guy Coder: Z drugiej strony film, do którego zamieściłeś link, wydaje się mówić coś innego niż na początku twojej odpowiedzi, a mianowicie, że język powinien zapewniać pewne podstawowe funkcje, które pozwolą jego użytkownikom (programistom) na rozszerz język (dodaj nowe biblioteki). Nie mówi, że podstawowy język powinien rosnąć w nieskończoność.
Giorgio

1

Oto duży cytat z Hardcore Visual Basic Bruce'a McKinneya , który z kolei przekazuje słowa do ust projektantów BASIC, Kemeny i Kurtz . Podkreśla moje.

Każdy język komputerowy ma swój własny klimat, swoją atmosferę, swój własny duch. Nie możesz tak naprawdę zdefiniować tego ducha, ale wiesz, co to jest, kiedy go widzisz. Myślę o Basicu jako antytezie oświadczenia przypisywanego Albertowi Einsteinowi:

Spraw, aby wszystko było tak proste, jak to możliwe, ale nie prostsze.

Gdyby ten cytat został napisany przez pierwotnych projektantów Basic, Johna Kemeny i Thomasa Kurtza, zostałby jeszcze bardziej uproszczony:

Uprość wszystko, niż to możliwe.

Jest to sprzeczność, na której żyją programiści Visual Basic. Chcemy, aby rzeczy były proste, eleganckie i intuicyjne - ale tak nie jest. Chcemy, aby nasze programy modelowały rzeczywistość - ale tak nie jest. Chcemy, aby nasz język działał w taki sposób, w jaki myślimy, a nie w taki sposób, w jaki chcą nas myśleć komputery lub systemy operacyjne - ale nie jesteśmy gotowi zapłacić ceny .


W pokrewnej uwadze fakt, że konstrukcja języka „może” zostać stworzona do wielu celów, nie oznacza, że ​​taki projekt jest lepszy niż posiadanie różnych konstrukcji do tych różnych celów. Na przykład C używa typów niepodpisanych zarówno do reprezentowania wielkości liczbowych, jak i do reprezentowania członków owijającego się pierścienia algebraicznego. Dodanie liczby o dowolnym rozmiarze lub sygnaturze do pierścienia powinno dać element tego samego pierścienia, a dodanie dwóch liczb o dowolnym rozmiarze i sygnaturze powinno dać wynik wystarczająco duży, aby obsłużyć dowolną wartość dowolnego argumentu. Używanie niepodpisanych typów do obu celów ...
supercat

... oznacza, że ​​reguły C muszą czasem traktować je jako liczby, a czasem jako członków pierścienia, w sposób, który prawie uniemożliwia napisanie czystego, przenośnego kodu.
supercat

1

Ale czy zasadę KISS można zastosować także do projektowania języka programowania? Czy znasz jakieś języki programowania, które zostały zaprojektowane specjalnie z myślą o tej zasadzie, tj. „Pozwalają przeciętnemu programistowi w przeciętnych warunkach pracy pisać i utrzymywać jak najwięcej kodu przy minimalnym wysiłku poznawczym”?

Dobrze, że wyjaśniłeś, co rozumiesz przez „prosty”, ponieważ moim zdaniem prosty język programowania to taki, który ma minimalną składnię i kilka funkcji (Scheme, Forth, ML), co nie przekłada się bezpośrednio na twoją definicję. Myślę, że naprawdę szukasz projektowania języków z myślą o RAD (szybkie tworzenie aplikacji), a jest ich całkiem sporo. Zobacz ten wątek StackOverflow, na przykład: /programming/66227/what-is-the-best-multi-platform-rad-language


„ponieważ moim zdaniem prosty język programowania to taki, który ma minimalną składnię i kilka funkcji (Scheme, Forth, ML)”: Cóż, tak naprawdę skopiowałem definicję z wikipedii, ale zwykle identyfikuję te dwie rzeczy. Np. Schematu można się nauczyć bardzo szybko, a potem mogę skoncentrować się na rozwiązaniu problemu. Inne języki (takie jak C ++, których używam w pracy) stale się rozwijają i trzeba cały czas uczyć się nowych rzeczy. Ponadto kod staje się mniej konserwowalny, ponieważ różni programiści używają różnych podzbiorów języka. Tak więc uważam SML i schemat za „proste”.
Giorgio

1

Dziwi mnie, że nikt jeszcze nie wspominał o C, mimo że stawia on prostotę na pierwszym miejscu na kilka ważnych sposobów, często w tak radykalny sposób, że programiści nie doceniają prostoty:

  • Nie ma ukrytej magii. Jeśli piszesz a + bw C, masz gwarancję, że skompiluje się co najwyżej do jednej instrukcji asemblera.

    Nawet w stosunkowo prostych językach, takich jak Java, taka prosta instrukcja a + bmoże zająć kilka mikrosekund (jeśli zmienne są łańcuchami). Inne języki dodają do tego wiele, wiele więcej, dzięki ekstremalnemu przykładowi C ++, gdzie a + bmoże być przeciążony, aby pojawiały się różowe słonie. Nie w C: jeśli nie jest to wywołanie funkcji, nie zajmie to więcej niż kilka nanosekund. Ta przewidywalność działania jest jedną z kluczowych cech C i jest z pewnością formą prostoty.

  • Typy danych są tak proste, jak mogą być, przy jednoczesnym opisywaniu wszystkich interesujących struktur danych, które warto zbudować w pamięci: istnieją tylko podstawowe typy, które procesor może obsłużyć + agregacja ( struct) + powtarzanie (tablice) + referencje (wskaźniki) ).

    Prawdą jest, że pod tym względem różne języki oparte na seplenienie są znacznie prostsze niż C. Nie próbują jednak pozwolić programiście swobodnie manipulować pamięcią, podobnie jak C.

  • Ortogonalność funkcji: Możesz dowolnie łączyć funkcje i będą one działać zgodnie z oczekiwaniami. Wiele języków zawodzi, ponieważ niektóre konstrukcje pojawiają się tylko w określonych kontekstach.

    Weźmy na przykład tablice o zmiennej długości w C i C ++: C zezwala na wszędzie czas działania, podczas gdy najbardziej liberalne żądania rozszerzenia standardu C ++ pozwalają tylko w pewnych kontekstach, takich jak tablice automatyczne, a nawet tylko w pierwszym wymiarze. Dzięki temu C może obsługiwać prawdziwe wielowymiarowe tablice o rozmiarach znanych tylko w czasie wykonywania, podczas gdy programiści C ++ są zmuszeni do pisania data[k + (j + i*lineLength)*lineCount]w kółko.

    Innym przykładem tego jest wskaźnik: Wskaźnik danych w C to tak naprawdę nic więcej lub mniej niż tylko zmienna zawierająca adres pamięci innej zmiennej. Ponieważ sam wskaźnik jest zmienną, podwójny wskaźnik jest dobrze zdefiniowaną rzeczą. To znaczy biorąc pod uwagę co inti int*czym jest, jasne jest, co int**musi być. Porównaj to z referencjami w C ++, w których absolutnie nie masz pojęcia, co int&&ma znaczenie inti int&!)

Prawdą jest, że właśnie ta prostota sprawiła, że ​​C tak bardzo nienawidzi: prostota języka daje programistom więcej swobody niż jest dla nich dobra, co prowadzi do wielu problemów związanych z nieokreślonym zachowaniem i błędnymi wskazówkami. Zwłaszcza prostota ortogonalności, która pozwala programiście zdefiniować zmienną int (*array[m])(struct foo* (*arg)[n])tego typu, która ma tendencję do wywoływania bólów głowy u czytelników, ponieważ naprawdę złożone rzeczy mogą być wyrażone w bardzo zwięzłej formie przez liberalne połączenie kilku prostych cech . Jest to rodzaj prostoty, w której C wyróżnia się i która daje mu reputację trudnego języka.

Ponadto prostota języka zmusza programistę do napisania o wiele więcej kodu niż języków bogatych w funkcje, zapewniając bardziej podatny grunt dla rozkwitów błędów. Niemniej jednak pozostaje najprostszym możliwym językiem wysokiego poziomu, jeśli twoim głównym celem jest zaprogramowanie prawdziwego komputera, a nie jakiejś maszyny wirtualnej.


Czy downvoter może zostawić wiadomość wyjaśniającą powód swojego głosowania?
Giorgio,

C to bałagan. Spróbuj ustalić, co otrzymasz, jeśli dodasz podpisane zwarcie do niepodpisanego długiego i zapisz wynik w postaci int. Nawet bez „długiej długiej” ma osiem różnych typów całkowitych. To nie jest proste.
Simon B

@ SimonB Najwyraźniej nie rozumiesz, o czym jest mój post. Prostota dotycząca typów liczb całkowitych jest następująca: typ liczb całkowitych ma rozmiar (w bajtach i bitach) i może być podpisany lub niepodpisany. Możesz użyć dowolnej kombinacji tych dwóch funkcji ortogonalnych. O tej ortogonalności mówię. C ma wszystkie funkcje wymagane do pełnego wykorzystania prawdziwego sprzętu, co pociąga za sobą pewną złożoność. Jednak sposób, w jaki C radzi sobie z tą złożonością, polega na łączeniu prostych pojęć w ortogonalny sposób, aby pozwolić programistowi robić złożone rzeczy.
cmaster

0

Java Wikipedia - chociaż uproszczenie nie zostało wyraźnie powiedziane w Wikipedii, wielokrotnie wspomniano o uproszczeniu i było oryginalnym celem projektowym, ponieważ jedynym poważnym językiem zdolnym do OO (termin używany luźno) w tamtych czasach był C ++, który, jak wszyscy wiemy, jest potężny ale ma więcej niż kilka pułapek dla nieostrożnych.

JVM został pomyślany jako sposób na uproszczenie rozwoju na wielu platformach, a „Napisz raz uruchom w dowolnym miejscu” stało się mantrą Java na kilka lat - ponownie, celem było proste wdrożenie tego frameworka.

Uważam, że C # należy do tej kategorii uproszczenia języka.


Czy masz na myśli, że C # został pierwotnie zaprojektowany jako uproszczenie C ++?
Giorgio,

2
C ++ i OO? Alan Kay tak nie uważa. C # Sinplyfication ???? Nie wiem, co masz na myśli przez proste. Myślę, że najlepiej byłoby powiedzieć, że przed zadeklarowaniem rzeczy jako takich. LISP jest prosty, ponieważ ma bardzo mało składni. C # wręcz przeciwnie ma mnóstwo składni i słów kluczowych.
AndreasScheinert,

Możliwość uproszczenia rozwoju między platformami nie oznacza, że ​​sam język jest prosty. Coś może być wieloplatformowe, ale samo w sobie nie jest proste.
Bryan Oakley,

@Bryan Agreed - projekt Java wziął pod uwagę, że programy wieloplatformowe nie były (w tym czasie) proste, a do tworzenia prostych programów potrzebny był prosty język i trzeba było usunąć złożoność obsługi kodu specyficznego dla platformy w samym programie.
mattnz,

2
@Giorgio C # to przeróbka Javy. Java miała być zarówno mniej złożona niż C ++ (np. Brak wielokrotnego dziedziczenia), a także coś znacznie większego (np. Ogromna standardowa biblioteka, odśmiecanie).
Sean McSomething

-2

Hm ... to jest trudne pytanie, na które należy odpowiedzieć „pozytywnie”, ponieważ kiedy myślę o prostocie projektowania języka programowania (i czym „łatwiej” pracować), od razu myślę o:

  1. „Czytelność” kodu - jak dobrze język hermetyzuje obiekty, metody itp.
  2. Spójność językowych interfejsów API i interfejsów.

Istnieje wiele języków, które robią te rzeczy dobrze - ale w mojej głowie pojawia się język, który nie radzi sobie dobrze „jako język programowania”: PHP.

[Oświadczenie - napisałem PHP, a PHP jest nadal moim „idź do języka” dla prostych projektów internetowych. To jest krytyka miłości ...]

Po pierwsze, PHP ma się dobrze w środowisku, w którym zwykle działa na serwerach internetowych. Jest łatwy w konfiguracji, łatwy w utrzymaniu itp.

Gdzie walczę z PHP: kiedy chcesz zrobić coś „niezwykłego” - coś, czego zwykle nie robisz regularnie (w przypadku, gdy myślę, że to konsumowanie usługi internetowej SOAP - nie coś, co mam dużo z PHP), masz do czynienia z dwiema opcjami:

1) Różne rozszerzenia open source do PHP. Model obiektowy PHP jest na tyle luźny, że projektowanie interfejsu również nie jest zbyt spójne w zależności od biblioteki, od dewelopera do programisty. W konfrontacji z zestawem kodu, w którym ktoś korzystał z biblioteki, o której nigdy nie słyszałeś, spędzasz dużo czasu zastanawiając się, co to do cholery robi, ponieważ język pozwala na luźne tworzenie API / bibliotek.

2) Funkcje „wbudowane” - których jest wiele . Przeszedłem przez kilka króliczych dziur, albo znajdując inną bibliotekę, albo implementując trochę funkcjonalności, aby jakoś później się natknąćimpossiblyfound_basefunction()

Moim zdaniem prostota to konsekwencja.


-3

Teraz podejście KISS do języków programowania jest zabawnym pojęciem, przynajmniej jeśli uważasz, że języki programowania są warstwą abstrakcji w zestawie instrukcji procesora itp. Jeśli nie zdefiniujesz dokładniej „KISS”. Mówię tu tylko, że wózek KISS jest w pełni zastosowany do samochodu.

Teraz inną interpretacją KISS może być coś w rodzaju „elegancko wykonane bez zbędnych ozdób i niezbyt skomplikowane”. Szczególnie można argumentować, że nie powinno być zbyt wielu konkretnych przypadków na podobne rzeczy itp. Zwykle matematyka jest całkiem dobra w sprowadzaniu rzeczy do swojej istoty, i - o dziwo - matematycy spędzili trochę czasu myśląc o programowaniu i komputerach .

Do programowania istnieją 2 dość znane modele abstrakcyjne:

  • Jednym z nich jest maszyna Turinga, która definiuje maszynę i prosty model instruktażowy, który jest w stanie obliczyć wszystko, co komputer może zrobić.
  • Drugim jest Lambda-Calculus autorstwa Church et. glin. to jest równoważne pod względem mocy

Zabawne jest to: chociaż maszyna Turinga ma dość prosty układ, nie jest to system łatwy w obsłudze i nie sądzę, że kwalifikuje się do „inteligentnego KISS”. Ale Lambda Calculus ma więcej wspólnego z językami programowania, które znamy - a dzięki pionierskim funkcjom rachunku lambda Lisp i Scheme dotarł do wielu języków.

Lisp i Scheme są NAPRAWDĘ proste, przynajmniej pod względem składniowym. Składnia jest poważnym problemem związanym z językami programowania (prawdopodobnie dlatego są ciągle wymyślane na nowo). W przypadku C ++ ludzki mózg prawie nie jest w stanie przewidzieć, w jaki sposób kompilator interpretuje niektóre linie źródłowe).

Lisps całkowicie zmniejszają złożoność syntaktyczną, wprowadzając jedną wspólną formę poleceń:

(command param1 param2 ...)

Może to być wywołanie metody, takie jak

(max 1 2 3 4)

a także gałąź if, pętla itp.

(if (< 1 2) 
    (write 4)
    (write 5))

(cały kod jest pseudo-Lisp / dialekt agnostyczny)

Formularz

(command param1 param2 ...)

można również interpretować jako listę

(item1 item2 item3)

I to jest podstawa prostoty i piękna Lisps. Ponieważ listy zagnieżdżone (jak w ifprzykładzie instrukcji) stanowią drzewa i można je łatwo zrozumieć zarówno przez maszynę, jak i człowieka przed maszyną.

Inną cechą Lisps są makra, nie będę wchodził tutaj w nieprzyzwoite szczegóły, ale ponieważ nie ma różnicy składniowej między normalnymi wywołaniami funkcji a "Składnią (jajko dla pętli, deklaracja zmiennej itp.), Wszystko, co parser musi obsłużyć w innych języki programowania) możesz stworzyć własną składnię. Makra to w istocie Manipulacje drzewem, które tworzą twój program.

Myślę, że Lisp ma KISS do programowania. To, że możesz manipulować składnią za pomocą makr, doprowadziło do zjawiska, które Lisp ewoluowało dość dynamicznie. Potrzebujesz nowej funkcji języka, takiej jak - powiedzmy orientacja obiektowa - po prostu napisz system OOP z makrami!

Podczas gdy C zostało przedłużone rondo 2 razy z funkcjami OOP (C ++, Obj. C), Lisp został przedłużony wiele razy, w końcu zwyciężył.

To kolejne dziwactwo na temat Lisp, ewoluuje (patrz Clojure i Clojurescript, aby uzyskać ciekawe nowe Mutacje lisp).

Ze względu na swoje właściwości KISS niektórzy preferują Lisps. Podobnie jak kontury Fogusa w jego projekcie języka edukacyjnego ( http://blog.fogus.me/2013/01/21/enfield-a-programming-language-designed-for-pedagogy/ )

Na początek jestem głęboko przekonany, że uczenie się nowych, a czasem skomplikowanych tematów jest wręcz szkodliwe dla przeciążania uczniów niepoważnymi regułami składni. Dlatego Enfield został zaprojektowany z minimalnymi regułami składni i co jest bardziej minimalne niż składnia podobna do Lisp.

2
OP dość jasno definiuje KISS w kontekście tego pytania: „pozwól przeciętnemu programistowi w przeciętnych warunkach pracy pisać i utrzymywać jak najwięcej kodu przy minimalnym wysiłku poznawczym” . OP wspomina również o „zainteresowaniu poznaniem (udokumentowanych) intencji projektantów, a nie osobistej opinii na temat określonego języka programowania”
komentuje
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.