Jak zaprojektowałbyś język programowania? [Zamknięte]

41

Gdybyś zaprojektował język programowania, jak byś to zrobił? Jakie funkcje byś wprowadził? Co byś pominął? Pisanie statyczne czy dynamiczne? Mocno czy słabo napisane? Skompilowane lub zinterpretowane? Uzasadnij swoje odpowiedzi.

Chinmay Kanchi
źródło
12
To pytanie jest zbyt niejasne. Naprawdę nie można omawiać cech językowych, dopóki nie zostanie określony cel języka.
blucz
1
Jeśli możesz głosować i uważasz, że jest to przydatne pytanie lub poniżej znajdziesz przydatne odpowiedzi, zagłosuj. Witryny StackExchange potrzebują głosów, aby zbudować dobrą społeczność. Możesz dać 30 głosów dziennie, nie marnuj ich. Szczególnie użytkownicy o wysokiej reputacji i niskiej liczbie
Maniero
3
Stworzyłbym język bardzo wysokiego poziomu za pomocą jednej metody: public void DoWhatIMeant ();
Dave
6
idealny język programowania? ... Zmusiłbym kompilator do czytania w myślach i generowania programu dokładnie tak, jak tego chcę .. :) może to chwilę potrwać, ale byłoby warto.
WalterJ89,
2
Kompilacja i interpretacja to cechy… cóż, kompilatora lub tłumacza (duh), a nie języka. Wszystkie języki mogą być implementowane przez kompilator lub tłumacza. W rzeczywistości prawie wszystkie są. Istnieją kompilatory dla Ruby, Python, ECMAScript, PHP, są interpretatory dla C, C ++, Java, Haskell, ...
Jörg W Mittag

Odpowiedzi:

55
  • Zdecydowanie uważam, że funkcjonalne języki programowania się zaakceptują, więc mój język będzie funkcjonalny. Zobacz efekty oswajania za pomocą programowania funkcjonalnego

  • Myślę, że procesory wkrótce będą miały setki rdzeni, a wątkom będzie do cholery zarządzać. Zatem model aktora jest koniecznością zamiast wątków. Zobacz Erlang - oprogramowanie dla współczesnego świata

  • Myślę też, że OOP nie powiodło się, założono, że komunikacja między obiektami jest asynchroniczna . Myślę więc, że potrzebujemy przekazywania wiadomości z niezmiennymi wiadomościami. Wyślij i zapomnij. Jak w modelu Actor. Zobacz Programowanie obiektowe: zła ścieżka?

  • Myślę, że dobrze byłoby mieć pisanie statyczne , więc błędy są wychwytywane wcześniej w cyklu programowania. Ale użyłbym wnioskowania typu jak w Haskell, aby deweloper nie musiał pisać tego typu wszędzie w kodzie, jak w C, C # i Javie. Zobacz: Learn You A Haskell for Great Good

  • Zaprojektowałbym też świetną bibliotekę interfejsu użytkownika , z deklaratywnym układem , tak jak w WPF i Androidzie. Ale chciałbym mieć to tak, jak w Funkcjonalnym Programowaniu Reaktywnym .

Mój język byłby więc jak współbieżność w Erlangu, ale z pisaniem jak w Haskell i strukturą GUI jak w WPF.NET.

Jonas
źródło
4
brzmi jak Scala, z wyjątkiem może świetnej biblioteki interfejsu użytkownika.
Ape-inago,
Myślałem, że Scala ma przekazywanie wiadomości i aktorów. Chyba nie mam związku z OOP.
Ape-inago,
@Jonas: wygląda świetnie :) Nie wiem dużo o Modelu Aktora, czy jest podobny do tego, co Go zrobił z goroutynami?
Matthieu M.,
1
Sceptycznie podchodzę tylko do pisania statycznego. Zdecydowanie wolałbym mocne niż słabe pisanie, ale czasem pisanie statyczne jest zbyt restrykcyjne. Ale nie znam Haskella i słyszałem tylko dobre rzeczy o jego systemie pisania :)
sakisk
1
Szczęście OOP, szczerze mówiąc, polega na tym, że właściwie żaden język „zorientowany obiektowo” tak naprawdę go nie implementuje . Najprościej po prostu przekształć model obiektowy w język proceduralny i nazwij go dniem. Wolałbym, żeby Smalltalk przyłapał się na sobie bardziej niż na zachęcaniu każdego języka proceduralnego, który odmawia powiedzenia „Eh, możemy zrobić coś w rodzaju - może takiego” i całkowicie pominąć cel OOP.
cHao
22

Uwaga: Użyłem składni podobnej do C do opisania funkcji w tym poście, ale nie jestem wybredny w samej składni, o ile nie jest to coś śmiesznego, jak wszystkie słowa kluczowe będące CAPS.

1. System pisania

Najważniejszą funkcją, której chciałbym w danym języku, jest pisanie statyczne z opcjonalnym pisaniem dynamicznym. Powodem jest to, że pisanie statyczne pozwala a) wcześnie wychwytywać błędy, a nie późno, oraz b) większość kodu jest domyślnie wpisywana statycznie, niezależnie od tego, czy język je rozróżnia. Istnieje jednak kilka przypadków użycia, w których dynamiczne pisanie jest niezwykle przydatne. Na przykład podczas odczytu danych z pliku często masz pola różnych typów, a dynamiczne pisanie ułatwia heterogeniczne kontenery. Tak więc mój idealny język miałby coś takiego:

//variable declarations
int anInt = 42 //anInt is now irrevocably an integer and assigning another type to it is an error
vartype aVariable = 42 //aVariable is currently an integer, but any type can be assigned to it in the future

//function definitions
int countElements(Collection c)
{
  return c.count();
} 

//c HAS to be a collection, since countElements doesn't make sense otherwise

void addToCollection(Collection& c, vartype v) 
{
  c.append(v)
}

//c is passed by reference here

2. Opracowane a zinterpretowane

Chciałbym, aby język był albo skompilowany z wyprzedzeniem, albo JIT skompilowany, ale nie wyłącznie interpretowany, ponieważ powodem jest szybkość. Jest to związane z punktem 1 , ponieważ optymalizujący kompilator / jitter będzie miał znacznie łatwiejszy czas na optymalizację kodu o typie statycznym, a kod o typie dynamicznym można po prostu pozostawić bez zmian.

3. Zamknięcia

Język musi obsługiwać konstrukcje programowania funkcjonalnego, a funkcje powinny być obiektami najwyższej klasy.

4. Zorientowany obiektowo

Język powinien umożliwiać pisanie kodu obiektowego, ale powinien być również dozwolony prosty kod imperatywny. tzn. powinno być możliwe napisanie programu hello world takiego:

int main(string<> args=null)
{
  printf("hello, world"); 
  return 0;
}

// this code also demonstrates two other features,
// default arguments for functions (not explained further)
// and immutable lists like string<> (see 6. Built-in datatypes)

5. Przestrzenie nazw

Przestrzenie nazw są dobrą rzeczą. Bardzo niewiele rzeczy powinno trafić do globalnej przestrzeni nazw. Ale jeśli musisz umieścić rzeczy w globalnej przestrzeni nazw, możesz (ala C ++).

6. Wbudowane typy danych

Język musi mieć, jako wbudowane typy danych, następujące konstrukcje:

  • Typ intlub typy danych. Jeśli jest tylko jeden inttyp, powinien mieć nieograniczony zasięg. Jeśli jest ich więcej, powinno być niejawne upcasting do najmniejszego typu, który jest w stanie utrzymać wynik obliczeń, przy czym typ nieograniczonego zakresu jest największy.
  • Pojedynczy wbudowany floattyp binarny , który jest równoważny z IEEE 754double
  • Zmienny listtyp, który jest implementowany jako podwójnie połączona lista lub blok ciągłej pamięci przechowującej wskaźniki do każdego elementu
  • Niezmienny listtyp, który działa jak tablica, ale którego rozmiaru nie można zmienić po utworzeniu
  • stringTypy zmienne i niezmienne , przy czym domyślnie są niezmienne.
  • A maplub dicttyp, który jest zmienny i zawiera niezmienne klucze oraz zmienne i / lub niezmienne wartości.
  • Wbudowane typy kolekcji powinny być domyślnie jednorodne, ale w vartyperazie potrzeby mogą być d
  • booleantyp
  • A nulllub nonetyp, który można przypisać do zmiennej dowolnego typu.
  • Zmienne i niezmienne settypy
  • decimalTyp, który implementuje zmienne dziesiętnych liczb zmiennoprzecinkowych
  • fixedRodzaju, które realizuje szereg stałoprzecinkowych

Te decimal, floatoraz fixedrodzaje powinny dzielić dokładny sam interfejs publiczny (albo poprzez dziedziczenie lub kaczka wpisywanie), pozwalając im być transparentnie przekazywane i wrócił z funkcji. Można wywołać typ nadrzędny real.

7. Zadzwoń według wartości i referencji

Powinieneś być w stanie wywoływać funkcje zarówno według wartości, jak i odwołania, przy czym domyślna wartość to (tzn. Kopia argumentu jest tworzona i obsługiwana w funkcji).

8. Wskaźniki

Język powinien mieć wskaźniki i umożliwiać arytmetykę wskaźników. Wskaźniki można wpisywać tylko statycznie (aby uniknąć koszmaru, którym jest a void*). vartypewskaźniki są wyraźnie zabronione. Posiadanie wskaźników i arytmetyki wskaźników pozwala na poważne wykorzystanie języka jako języka programowania systemów.

9. Montaż w linii

W związku z 8. Język powinien umożliwiać wstawianie kodu języka asemblera w sytuacjach, gdy jest to konieczne.

10. Bezpieczeństwo

Język powinien być w większości bezpieczny w obsłudze, obsługujący obsługę wyjątków itp. Arytmetyka wskaźnika i wbudowany zestaw mogą być przeniesione do części kodu wyraźnie oznaczonych jako niebezpieczne. Niebezpieczny kod jest dozwolony, ale zdecydowanie odradzany.

11. Nieokreślone zachowanie

Standard językowy powinien określać, jak program ma się zachowywać we wszystkich okolicznościach, z wyjątkiem kodu wyraźnie oznaczonego jako niebezpieczny, tzn. Nie powinno być niezdefiniowanego zachowania poza niebezpiecznymi blokami. Pozwala to na używanie tego języka jako realnego języka programowania aplikacji, a jednocześnie pozwala powiedzieć, napisać w nim system operacyjny.

To wszystko, co mogę teraz wymyślić, ale będę edytować / aktualizować post, gdy będę myśleć o kolejnych rzeczach.

Chinmay Kanchi
źródło
5
Spójrz na „D Programming Language”: digitalmars.com/d
Wizard79
O ile pamiętam, D nie ma opcjonalnego pisania dynamicznego ani wbudowanego typu liczby całkowitej o nieograniczonym zakresie. Typ liczb całkowitych nie stanowi większego problemu, ale brak opcjonalnego pisania dynamicznego czyni go dość nieatrakcyjnym.
Chinmay Kanchi,
1
Naprawdę dodałbym decimaltutaj typ.
konfigurator
3
„Typ zerowy lub żaden, który można przypisać do zmiennej dowolnego typu.” - W tym logiczne? :-p
Timwi
1
Nie widzę słowa „elastyczny” w oryginalnym poście. Inline Assembler nie przyszedł mi do głowy jako najwyższy wymóg dla języka programowania. Być może według Felixa von Leitnera obecnie pisanie Asemblera daje głównie powolne nieprawidłowe wyniki.
LennyProgrammers,
7

Tak wyglądałby mój wymarzony język programowania:

  • Potężny system typów statycznych z pewną obsługą pisania zależnego.
  • Opcjonalne pisanie dynamiczne.
  • Wieża numeryczna a la Lisp, ale wpisana statycznie.
  • Macros a la Lisp.
  • Przede wszystkim funkcjonalny język programowania z podstawową obsługą programowania imperatywnego (jak rodzina ML).
  • Zbieranie śmieci.
  • Wnioskowanie typu.
  • Kontynuacje
  • Opcjonalna leniwa semantyka.
  • Wszystkie konstrukcje kontrolne byłyby dostarczane w postaci funkcji bibliotecznych. (Można to zrobić za pomocą dwóch ostatnich funkcji).
  • Minimalna składnia (nie tak mała jak Lisps, ale coś w rodzaju Ioke / Seph.)
missingfaktor
źródło
Brzmi dobrze. Jednak tak naprawdę nie widziałem dobrego sposobu na tworzenie statycznie bezpiecznych makr.
Jörg W Mittag,
@ Jörg: Nemerle?
missingfaktor,
W Smalltalk wszystkie struktury kontrolne są w rzeczywistości metodami i nie używają kontynuacji w ich implementacji. Jedno nie jest potrzebne dla drugiego.
Oak
@Oak, czy możesz wdrożyć Pythona yieldw Smalltalk? Powinien być tak czysty w użyciu.
missingfaktor
Mechanizm wydajnościowy jest już zaimplementowany w smalltalk jako metoda biblioteczna, bez kontynuacji.
Dąb
6

Zaprojektowałbym go prawie jak C #, ale Microsoft mnie pobił. :)

(Poza tym, że mój byłby mniej przemyślany i bardziej amatorski.)

Nie mam nic przeciwko temu, czy jest to kompilowane, czy interpretowane, więc nie muszę tego uzasadniać.

W odniesieniu do silnego pisania statycznego trudno mi docenić, dlaczego wymaga to nawet uzasadnienia. Pisanie statyczne to funkcja wychwytująca błędy podczas kompilacji. Pisanie dynamiczne to brak tej funkcji i odracza błędy do czasu uruchomienia. Z mojego osobistego doświadczenia miałem kilka przypadków użycia, w których dynamiczne wysyłanie miało sens i było przydatne, więc zwoje, które musiałem przejść w C # przed 4.0, aby je uzyskać, były łatwo uzasadnione. W wersji C # 4.0 nie muszę nawet tego uzasadniać, ponieważ mamy teraz dynamiczną wysyłkę.

Jednak prawdopodobnie stworzyłbym nową składnię zamiast trzymania się tak religijnie starej składni C, jak C #. Instrukcja switch jest szczególnie okropna, a ja też nie lubię składni obsady (jest to niewłaściwa metoda). Nie kłopoczę się jednak szczegółami składni, więc nie muszę tego szczegółowo wyjaśniać, z wyjątkiem tego, że nie chciałbym, żeby był tak gadatliwy jak Visual Basic.

Co jeszcze chciałbyś, żebym uzasadnił?

Timwi
źródło
+1 Dobra odpowiedź! Później też opublikuję jeden z moich.
Chinmay Kanchi,
4
C # to potężny język, ale jego składnia jest często nieporządna. Myślę, że dzieje się tak, ponieważ tak wielu z tych funkcji nie było w oryginalnym projekcie.
Casebash
Stąd „4.0”, tak myślę.
Mark C
5

Oto lista funkcji, które chciałbym wprowadzić:


Lisp jak składnia

Styl Lisp

Plusy :

  • Łatwo rozszerzalna składnia. Czy kiedykolwiek próbowałeś wdrożyć pętlę foreach w C? To nie jest do końca łatwe. (Pamiętaj, że to zrobiłem ).
  • Homoiconicity. Możesz po prostu(eval "your data files")

Wady :

  • Zagnieżdżony polski zapis jest często trudny do odczytania

Programowanie funkcjonalne

Styl Haskell

Plusy :

  • Łatwa współbieżność, cały kod jest bezpieczny dla wątków.

Wady :

  • Trudno jest wdrożyć efekty uboczne w czystym kodzie funkcjonalnym, chociaż monady wydają się wykonywać dobrą robotę.

Silne pisanie dynamiczne

Styl Python

Plusy :

  • Pisanie dynamiczne sprawia, że ​​kod jest czytelny, a silne pisanie może wyeliminować błędy pisowni

Realizacja :

Zezwól na przeciążenie funkcji na podstawie typów, podobnych do CL defgeneric:

(define (+ (a <int>) (b <int>))
  (ints-add a b))

(define (+ (a <string>) (b <string>))
  (string-concat a b))

(define (+ a b)
  (add-generic a b))

Kompilowalny i interpretowalny

Plusy :

  • Zwiększenie wydajności, jeśli zostanie skompilowane (zwykle prawda, nie zawsze)

Wady :

  • Może ograniczać funkcje w języku, ale llvm będzie dobrym wsparciem.

Programowanie systemów

Styl C.

Plusy :

  • Apeluje do bardzo nieznacznie szerszej grupy użytkowników.
  • Łatwiejsza interakcja aplikacji, jądra i sterowników urządzeń, jeśli wszystkie są napisane w tym samym języku

Wady :

  • Ogranicza abstrakcje w języku, dynamiczne pisanie często nie jest odpowiednie.

Makra higieniczne (styl CL i styl schematu)

Plusy :

  • Łatwo rozszerzyć język, szczególnie dzięki składni Lispy ™
  • Mówiłem to wcześniej, prawda?

Wady :

  • Niewiele, jeśli zrobiono to ze składnią Lispy ™

Pomyśl o tym, ten mniej więcej określa schemat, z wyjątkiem bitu kompilacji i programowania systemu. Można to obejść, używając libguile i pisząc te bity w C.

Joe D.
źródło
1
Spójrz na Ioke and Seph. To zadziwiające, o ile łatwiejszy do odczytania język można uzyskać, dodając bardzo małą składnię w porównaniu do S-Expressions, i nadal ma pełne możliwości makr. (Zasadniczo zamiast „każde wywołanie funkcji jest listą, a listy są pierwszej klasy”, „wszystko to jest wysyłanie wiadomości, a łańcuchy wiadomości są pierwszej klasy”. Zamiast listy, której carfunkcją i cdrargumentami, jest obiekt, którego namepole jest metodą, a którego argumentspole jest argumentem. Zamiast zagnieżdżania masz pola previ nextwskaźnik.)
Jörg W Mittag
Brzmi prawie dokładnie tak jak Clojure (zakładając, że używasz Mjolnir do generowania kodu natywnego na LLVM dla części programistycznej systemów - github.com/halgari/mjolnir )
mikera
3

Istnieje kilka języków, które uważam za cholernie dobre (C # jest moim ulubionym). Ponieważ jest to mój język fantasy, tak naprawdę chcę, aby miał:

  • Kick-ass oficjalna dokumentacja API. Java API jest taki dobry, a C # / .NET jest całkiem dobry. Ruby / Rails jest tutaj dość okropny.
  • Kick-ass oficjalna ogólna dokumentacja (instrukcje, typowe zastosowania, mnóstwo przykładowego kodu). C # /. Net nadaje się do tego.
  • Ogromna społeczność blogerów i rozwiązujących problemy StackOverflow, którzy pomagają mi w trudnych chwilach
  • Szeroka gama dobrze obsługiwanych, dobrze udokumentowanych i wydajnych wtyczek / bibliotek / rozszerzeń (Ruby / Rails ma „potężne”, ale żadne z pozostałych dwóch).
  • Jest dość stabilny - nie zmienia wszystkiego, aby co roku łamać większość istniejącego kodu (patrząc na ciebie, Ruby / Rails).
  • Nie jest zbyt stabilny - jest w stanie dostosować się do postępu w projektowaniu języka (patrząc na ciebie, c ++)
Fishtoaster
źródło
2
Punkty „Dokumentacja kick-ass” powinny obejmować PHP: D
Corey
3

Wskazówki kompilatora

Mówię o mnie, bum, ponieważ nie wiem zbyt wiele o projektowaniu języków, ale myślę, że funkcja, o której mówię, nazywa się podpowiedziami w innych językach. Może wskazówki kompilatora ?

Nie wiem, czy przeczytałem to w wersji roboczej Perl6, czy też było wtedy na haju, ale wyobrażam sobie język, w którym wszystko domyślnie jest luźne i logiczne. Ale jeśli chcesz naprawdę zwiększyć wydajność i powiedzieć, hej, ta wartość jest zawsze liczbą całkowitą lub nigdy nie jest zerowa, lub może być równoległa lub jest to bezstanowa, takie rzeczy ... Że kompilator może automatycznie przejść do miasta na tych specjalnie oznaczonych obszarach.

E: Będę wdzięczny za komentarze wyjaśniające, o co proszę, lub przytaczające przykłady, w których już to istnieje.

Mark Canlas
źródło
1
Możesz to zrobić w Common Lisp. Na przykład możesz powiedzieć kompilatorowi, że i jest liczbą całkowitą o rozsądnej wielkości. Jedną przydatną rzeczą jest to, że zmieniając wartości safetyi speed, często możesz albo sprawdzić i wymusić kompilator (aby znaleźć problemy), albo założyć, że to, co mówisz, jest prawdą (i skompilować szybszy kod).
David Thornley,
2

Aby wypróbować nowe pomysły:

Zrobiłbym dynamiczny funkcjonalny język programowania, który pozwala wykonywać wszystkie sztuczki wyrażania instrukcji i najprostszą składnię lambda z dopasowaniem wzorca. Włączono regułę zewnętrzną.

// a view pattern (or Active Pattern in F#)
default = \def val: !!val.Type val def

// usage of the pattern
greet = \name<(default "world") `and` hasType Str>:
  p "Hello, \{name}!"

(p "Enter your name", .input).greet // (, ) is a sequence expression, returning the last value

Oto wyjaśnienie:

default =ustawia pamięć, \def valrozpoczyna funkcję curry z dwoma argumentami, val.Typejest taki sam jak Type[val], !!konwertuje na wartość logiczną i można zastosować wartość logiczną, więc validef are after it.

f x= f[x]= x.f .f=f[]

i w greet, użył name<(default "world")i hasType Str>, oznacza to, że wzór default "world"zostanie użyty i związany z name. Domyślny wzorzec określa wartość domyślną. andto kolejny wzór, który łączy ze sobą dwa wzory. defaultwzór nie może zabraknąć podczas hasTypemoże zawieść. W takim przypadku zgłasza wyjątek.

Zmienne są w rzeczywistości magazynami, które można funkcjonalnie przekazywać, a tabele pamięci mogą być referencjami, tworzone i niszczone wraz ze zmianą zakresów.

Hashe i takie będą jak w Lua i JavaScript.

Jeśli mam stworzyć skompilowany język, zrobię F # dla Javy z funkcjami podobnymi do Haskella. Jest to czysto funkcjonalny język, z tą różnicą, że istnieje funkcja, która łączy Cytaty i Wyrazy Comp w celu osiągnięcia programowania imperatywnego poprzez pisanie bloków podobnych do pseudokodu.

Ming-Tang
źródło
1
Brzmi to trochę jak Erlang, funkcjonalny język programowania z dynamicznym typem i dodał do tego całkiem unikalną konstrukcję współbieżnego języka.
Jonas
2

Pamiętając, że jedynymi znanymi mi językami są PHP i javascript oraz że naprawdę powinienem nauczyć się jeszcze kilku przed zaprojektowaniem języka:

Składnia: Zastanów się dokładnie nad nazwami funkcji i kolejnością argumentów (tzn. Bądź mniej niechlujny niż PHP).

Cechy: Posiadają zestaw stringfunkcji, które działają na zmiennych jako ciąg bajtów, ale nie rozumieją tekstu, oraz zestaw textfunkcji, które rozumieją wiele kodowań i mogą działać na UTF-8 i innych ciągach wielobajtowych. (I mają wbudowane w język sprawdzanie poprawności kodowania, z funkcją, text.isValidEncoding(text, encoding)która powie ci, czy sekwencja bajtów jest zniekształcona i niebezpiecznie traktowana jako tekst.

Myślę, że podoba mi się pomysł silnego pisania statycznego, ale nigdy go nie użyłem, więc naprawdę nie mogę powiedzieć.

Wymuskany
źródło
2

Przed zaprojektowaniem języka programowania znajdę dobrą odpowiedź na pytanie: dlaczego potrzebujemy jeszcze jednego języka programowania? Kod Rosetta w chwili pisania tego tekstu wymienia 344 języki. Jeśli żadna z nich nie spełniła moich potrzeb, określenie, dlaczego tego nie zrobiły, określałoby punkt początkowy (najbliższe języki) i to, co do niego dodać.

Gdybym wygrał na loterii i z jakiegoś powodu nie miał nic lepszego do roboty, zacznę od Liskell i uczynię go pełnoprawnym językiem w przeciwieństwie do interfejsu GHC, a następnie ułatwię (i zautomatyzuje) FFI, aby móc użyć dowolnego Biblioteka C / C ++.

Larry Coleman
źródło
2

Dobry język to język, który jest:

  • łatwe do uzasadnienia (brak niejasnej składni)
  • pozwól wyrazić swoje pomysły przy minimalnym zniekształceniu
  • ukryj przed sobą szczegóły drobiazgowości (optymalizacja / zarządzanie zasobami)
  • łatwo równoległy (wiele rdzeni, przetwarzanie rozproszone)

Trudno jest zmienić to w listę funkcji, ale myślę, że Programowanie Funkcjonalne, mimo że nie wydaje się naturalne , jest bliższe temu niż programowanie imperatywne (szczególnie w ukrywaniu drobiazgowych szczegółów)

  • Interfejs C: C to lingua franca języków programowania, a liczba bibliotek opracowanych w C jest niesamowita. Dzięki łatwemu interfejsowi (np. Python) do C, język automatycznie korzysta ze wszystkich tych bibliotek, a także umożliwia wysyłanie ciężkich zadań, których nie można zoptymalizować wystarczająco blisko języka metalowego.
  • Rozproszony : podoba mi się podejście Go do wielowątkowości, z lekkimi procedurami, które środowisko wykonawcze wywołuje dla wątków w zależności od ich aktywności. Taki język zachęca programistę do rozumowania zadań i izolowania ich od siebie.
  • Śmieci : w dzisiejszych czasach jest rzeczą oczywistą;)
  • Niezmienny : o wiele łatwiej jest uzasadnić coś, co nigdy nie może mutować, o wiele łatwiej wdrożyć także wielowątkowość / przetwarzanie rozproszone (potrzebujesz tylko synchronizacji, aby obsłużyć czas życia, co jest zadaniem kompilatora)
  • Lambdas : tak mi się zdaje z pierwszorzędnymi funkcjami
  • Przekazywanie wiadomości : niezmienność oznacza brak muteksu, dlatego podążamy za sugestią Tony'ego Hoaresa
  • Moduły : nieco podobne do przestrzeni nazw, ale z lepszą enkapsulacją
  • Refleksja : obliczenia rozproszone wymagają serializacji, którą należy pozostawić kompilatorowi, a deserializację można łatwiej osiągnąć za pomocą jakiejś formy refleksji.
  • Statyczne mocne pisanie : im wcześniej zostanie wykryty błąd, tym mniej kosztuje

W tej chwili językiem bliższym tej liście jest prawdopodobnie Haskell:

  • brakuje rutyny: nie widziałem jeszcze naturalnego sposobu wyrażania równoległości w Haskell (choć może to być moja ignorancja ...)
  • ma niejasną składnię: jakoś wygląda na to, że programiści Haskell rozwijają się używając dziwnych operatorów zamiast słów. To może wydawać się sprytne, ale niewiele pomaga zrozumieć, co się dzieje.
Matthieu M.
źródło
2

Na twoje pierwsze pytanie: „jak byś to zrobił” - krótka odpowiedź, nie zrobiłbym tego. Nie mam wystarczającej teorii parsera / kompilatora, aby to wyciągnąć. Ale programuję od 25 lat, więc mam kilka pomysłów i opinii, którymi mogę się podzielić.

Po pierwsze, spróbuję wymyślić podejście OOP, które pozwala tworzyć naprawdę połączone modele. Rozumiem przez to, że modele są jedną z najważniejszych rzeczy w prawie każdym projekcie programistycznym - zawsze jest dużo cholernej pracy i ciągłego refaktoryzacji, aby wszystko było w porządku, i winię to za brak prawdziwej łączności w Języki OO.

Pozwól mi pokazać. Powiedzmy, że dom klasy ma właściwość Door.

var door = house.Door;

Masz teraz zmienną lokalną z odniesieniem do instancji Door.

Ale zastanów się, co się właśnie wydarzyło: właśnie zerwałeś Drzwi z Domu, a teraz z przyjemnością przechodzisz dookoła Drzwi, a reszta twojego kodu nie zna faktu, że Drzwi te są w rzeczywistości przymocowane do Domu.

Dla mnie jest to zasadniczo błędne.

I tak, wiem, można to „łatwo” naprawić indywidualnie dla każdego przypadku - w tym przypadku poprzez zachowanie odwrotnego odniesienia od wszystkich drzwi do domu, do którego jest on obecnie przyłączony. To oczywiście otwiera twój model na błędy, ponieważ Twoim obowiązkiem jest dokładnie utrzymywać dwa odwrotne odniesienia, więc ustawiasz właściwości House.Doors i Door.House na prywatne i dodajesz metody takie jak House.AddDoor (), House.RemoveDoor ( ), Door.SetHouse () itp. I połącz to wszystko, a następnie przetestuj urządzenie, aby upewnić się, że rzeczywiście działa.

Czy to nie brzmi jak dużo pracy, aby modelować tak prostą relację? Dużo kodu do utrzymania? Dużo kodu do refaktoryzacji w miarę ewolucji modelu?

Problemem są wskaźniki. Każdy język OO, który widziałem, z natury cierpi na to, że odwołanie do obiektu jest tak naprawdę wskaźnikiem, ponieważ tego właśnie używają komputery.

Wskaźniki nie są dobrym sposobem na modelowanie prawdziwego świata. Niezależnie od tego, jaki świat chcesz modelować, jest prawie pewne, że wszelkie relacje w tym świecie będą relacjami dwukierunkowymi. Wskaźniki wskazują tylko w jednym kierunku.

Chciałbym zobaczyć język, w którym podstawowym modelem danych jest wykres - w którym wszystkie relacje mają domyślnie dwa końce. To prawie na pewno zapewniłoby znacznie bardziej naturalne dopasowanie do modelowania świata rzeczywistego, co jest naprawdę jedyną rzeczą, do której potrzebujemy komputerów. (to i gry wideo.)

Nie mam pojęcia, jak wyglądałaby składnia takiego języka ani czy można go nawet wyrazić za pomocą tekstu. (Zastanawiałem się, czy taki język musiałby być w jakiś sposób graficzny)

Chciałbym również wyeliminować wszystkie formy stanu przypadkowego.

Na przykład przy tworzeniu stron internetowych spędzamy dużo czasu na kształtowaniu danych z baz danych, modeli biznesowych, modeli widoków do prezentacji ... następnie niektóre z tych danych są prezentowane w formularzach, co jest tak naprawdę kolejną transformacją. .. i stan wraca z formularzy, a następnie przekształcamy te dane i rzutujemy je z powrotem na model widoku, np. segregatory modelu widoku i takie ... następnie rzutujemy z modelu widoku z powrotem na model biznesowy model ... następnie używamy mapujących obiektowo-mapujących (lub pomruków) do transformacji danych z modelu widokowego i projekcji na relacyjną bazę danych ...

Czy to zaczyna brzmieć zbędnie? W którym momencie tego całego szaleństwa naprawdę osiągnęliśmy coś pożytecznego? Przez użyteczne mam na myśli coś namacalnego - coś, co użytkownik końcowy może zrozumieć i na czym mu zależy. W końcu godziny spędzone na budowaniu czegoś, co użytkownicy mogą zrozumieć, są naprawdę jedynymi dobrze spędzonymi godzinami. Cała reszta to skutki uboczne.

Chciałbym bardzo dynamicznego języka. Cykl zapisu / kompilacji / uruchamiania jest żmudną stratą czasu. Idealnie, język powinien po prostu dowiedzieć się, co się zmieniło, i w razie potrzeby skompilować / załadować w sposób przezroczysty w tle.

Idealnie byłoby, gdybyś nie musiał nawet naciskać „uruchom” - rzeczy powinny się dziać na ekranie, gdy wprowadzasz zmiany, natychmiast odzwierciedlając wprowadzone zmiany. Problem z cyklem zapisu / kompilacji / uruchamiania, a nawet bardziej bezpośrednim cyklem zapisu / uruchamiania, polega na tym, że jesteś zbyt rozłączony z tym, co robisz - aby czuć się związanym z naszą pracą, potrzebują natychmiastowej informacji zwrotnej, natychmiastowych wyników. Każde czekanie jest za długie!

Znów nie wiem nawet, czy można to osiągnąć za pomocą tradycyjnego IDE, czy też wymagałoby to zupełnie nowego rodzaju interfejsu.

Powinieneś być w stanie używać kombinacji słabego i mocnego pisania, niezależnie od tego, co najbardziej odpowiada problemowi, nad którym pracujesz.

Stan powinien być czymś, co w pełni zarządza językiem. Dlaczego powinieneś polegać na bazie danych w zakresie trwałości? Idealnie, chciałbym móc po prostu określić czas życia dowolnej zmiennej w modelu: jedno żądanie sieciowe, jedna sesja, 24 godziny, na stałe.

Dlaczego musimy wybierać spośród całej gamy rozwiązań pamięci masowej dla różnych mediów i warunków życia? - nie wspominając o transformacji i kształtowaniu danych w celu dopasowania do każdego nośnika; pamięć podręczna przeglądarki, baza danych, pamięć, dysk, kogo to obchodzi! Dane to dane. Miejsce przechowywania danych (i na jak długo) powinno być prostym wyborem, a nie bitwą przeciwko bogom!

Powodzenia z tym.

mindplay.dk
źródło
1

Prawdopodobnie byłby to język paradygmatu obsługujący następujące elementy:

  • Programowanie strukturalne / proceduralne
  • Programowanie obiektowe
  • Programowanie funkcjonalne

Dlaczego te Zorientowany obiektowo, ponieważ jest to świetny sposób na organizowanie dużych programów, szczególnie w celu organizowania danych. Ustrukturyzowane, ponieważ nie zawsze tego chcesz / potrzebujesz (OOP), ludzie powinni mieć wybór. Funkcjonalny, ponieważ ułatwia programistom debugowanie i sprawia, że ​​programy są bardziej przejrzyste.

Używałbym modelu Pythona z wciętymi blokami do oznaczania bloków kodu. Jest bardzo clen i miło czytać.

Kradłbym całkiem sporo pomysłów od Pythona, ponieważ Python jest bardzo fajnym językiem. Wziąłbym to za wyciąg i skopiowałem jego mapy, listę i krotki.

Teraz prawdopodobnie nie wziąłbym dynamicznych pojęć z Pythona: po pierwsze, prawdopodobnie byłby typowany w sposób jawny i statyczny. Myślę, że dzięki temu programy stają się bardziej przejrzyste. Zmienne prawdopodobnie wszystkie byłyby obiektami z metodami, wtedy możesz zrobić coś takiego, str.length()aby uzyskać długość łańcucha. W definicjach funkcji należy określić typ zwracanego argumentu i typy argumentów (obsługując również pewien rodzaj typów ogólnych).

Wróćmy do kopiowania z Pythona ;-). Uwielbiam to sposób na opcjonalne argumenty procedur, więc prawdopodobnie bym to miał. Python nie obsługuje jednak przeciążania procedur, chciałbym tego.

Spójrzmy na zajęcia, porzuciłbym wielokrotne dziedzictwo; łatwe do nadużyć. Zaimplementowałbym zakresy prywatne i podobne i prawdopodobnie zaimplementowałbym to tak, jak to się dzieje w C ++. Miałbym także abstrakcyjne klasy i interfejsy; Nie wierzę, że Python ma to.

Wspierałby klasy wewnętrzne, w rzeczywistości chciałbym bardzo silnego języka obiektowego.

Prawdopodobnie zostanie to zinterpretowane. Możliwe jest uzyskanie go bardzo szybko dzięki dobrej kompilacji JIT (chciałbym szybkiego języka, choć produktywność programisty byłaby na pierwszym miejscu), a kompilacja jest po prostu niekorzystna dla produktywności w wielu przypadkach. Języki interpretowane promują również niezależność platformy, co jest coraz ważniejsze każdego dnia.

Miałby wbudowaną obsługę Unicode; w dzisiejszych czasach internacjonalizacja ma duże znaczenie.

Zdecydowanie byłoby to śmieci. Cholera, nienawidzę samodzielnie zarządzać pamięcią; też nie sprzyja wydajności.

Wreszcie miałby dobrą bibliotekę standardową.

Wow, właśnie zdałem sobie sprawę, jak bardzo kocham Pythona.

Anto
źródło
Dlaczego Interpreted languages also promote platform independance? Sądzę, że jest więcej kompilatorów międzyplatformowych, a nie kompilatorów (procent), ale nie mogłem zrozumieć, dlaczego to zdanie powinno być prawdziwe? Myślę, że nie ma między nimi żadnej różnicy, jeśli chodzi o umiejętności na różnych platformach.
Mahdi
1

Przede wszystkim kupiłbym kilka książek o kompilatorach, kilka standardów i wziął kurs lub dwa w językach i kompilatorach. Chciałbym przyczynić PEP s i odwiedzić C ++ standardów posiedzeniach komisji. Dodałbym łatki do kompilatorów, których używam, mam nadzieję, że zarówno pod kątem funkcji, jak i błędów.

Potem wrócę i z przerażeniem spojrzę na tę listę, którą teraz wymyśliłem, czyli w jakich kierunkach pójdę z językiem, gdybym teraz zaczął:

  • Funkcjonalne , ponieważ obecnie nie znam się dobrze na żadnym funkcjonalnym języku, a stworzenie takiego byłoby świetnym sposobem na naukę. W przypadku, gdy nie następuje bezpośrednio: wszystko jest stałe .
  • Wypełniłbym je jak najwięcej wnioskowania typu, jak tylko mogłem w nim zmieścić, ale z opcją jawnego określenia interfejsów. Nie jestem pewien co do innych typów. Podwaja się to, ponieważ wszystkie funkcje są domyślnie ogólne .
  • Jak można się domyślić, z interfejsami ; to znaczy z typami, które zapewniają tylko obietnice dotyczące dostępnych operacji.
  • O ile wiem, stwierdzenie, czy język jest mocno lub słabo wpisany, nie ma w tym przypadku większego znaczenia. Nazwałbym to silnie wpisane, jak rzeczy nigdy się nie zmieniają co interfejsy realizują .
  • Byłoby dużo programowanie kontraktowe wsparcia. Ponownie, o ile mogę zmieścić: warunki wstępne i dodatkowe są koniecznością; Nie wiem, ile niezmienników ma znaczenie, jeśli chodzi o programowanie funkcjonalne.
  • W tym momencie rzuciłem okiem na języki, w których możesz formalnie udowodnić poprawność i sprawdzić, czy mogę coś stamtąd odebrać.
  • Chciałbym napisać niesamowitą bibliotekę testową . Nawet jeśli nie sprawię, że będzie to niesamowite, poświęcę przynajmniej sporo czasu na pracę nad nim, ponieważ uważam, że jest to coś, co powinien mieć każdy język.
  • Jeśli chodzi o składnię, język miałby albo znaczną spację i wyglądałby bardzo podobnie do Pythona , albo byłby oparty na Lojbanie i miałby wiele gramatyki i słownictwa. W pierwszym przypadku dołożyłbym wszelkich starań, aby gramatyka była jak najbardziej zbliżona do CFG.
  • Nie obchodzi mnie, czy ludzie, którzy wprowadzą ten język, skompilują go wcześniej, JIT, interpretują, intonują na ognisku , lub płacą dzieciom z college'u, aby je dla nich wykonali. Moja własna implementacja prawdopodobnie zacznie się jako interpreter lub kompilator języka C, a ostatecznie przejdzie do JITtera.

Widząc, że nawet te dość szerokie kwestie prawdopodobnie szybko by się zmieniły, gdybym zaczął wdrażać język, więc myślę, że wchodzenie w dalsze szczegóły nie jest konieczne.

Anton Golov
źródło
0

Gdybym miał czas, zaprojektowałbym lokalizowalny język programowania oparty na Scali, więc miałby większość swoich funkcji, z wyjątkiem prawdopodobnie XML. Moim celem jest stworzenie języka, który będzie czytał prawie naturalnie w językach o innej strukturze niż angielski, takich jak arabski (mój język ojczysty). Mam na myśli następujące funkcje:

  • #langDyrektywa dotycząca preprocesora , używana do informowania preprocesora o języku ludzkim używanym do programowania. Na przykład: #lang arpozwoliłby na użycie tego słowa فئةzamiast class, عرفzamiast def, i tak dalej. Słowa kluczowe specyficzne dla języka ludzkiego byłyby zdefiniowane w standardowych plikach preprocesora.
  • Procesor wstępny usunąłby niektóre opcjonalne słowa kluczowe, których jedynym celem jest zwiększenie przejrzystości kodu. Na przykład usunąłby „składa się z” in, class MyClass is composed of {aby się stać class MyClass {, i „as”, def MyMethod(x: Int) as {aby się stać def MyMethod(x: Int) {. W niektórych (ludzkich) językach kod byłby znacznie łatwiejszy do zrozumienia, szczególnie dla studentów.
  • Kompilator umożliwi korzystanie z notacji przedrostkowej w celu uzyskania dostępu do właściwości. Może to nie mieć sensu dla większości użytkowników języka łacińskiego, ale dla niektórych innych języków ma to sens. Na przykład dostęp do właściwości w języku arabskim jest zwykle przedrostkiem, tak jak w اعرض طول اسم محمد, co jest równoważne z print(length(name(Mohammad)))językiem programowania-angielskim. (Nawiasy podano dla przejrzystości).

Wierzę, że te minimalne zmiany w preprocesorze i kompilatorze znacznie uprościłyby programowanie osobom nieanglojęzycznym.

Hosam Aly
źródło
5
Microsoft (i kilka innych wcześniej) stworzył zlokalizowane wersje VBA (Visual Basic for Office). To był bałagan. Chociaż jest to miłe dla początkujących, młodych i nieanglojęzycznych osób czytających kod w języku ojczystym, bardzo trudno jest udostępniać kod osobom spoza kraju. W naszych czasach w Internecie praca w izolacji nie jest zbyt produktywna. Gdybym musiał polegać wyłącznie na źródłach francuskich (artykuły na blogach, książki itp.), Aby nauczyć się Scali (tak jak obecnie), brakowałbym wielu przydatnych informacji. Nie wspominając już o trudności / ilości pracy związanej z lokalizacją bibliotek ...
PhiLho
1
@PhiLho: Z pewnością masz rację. Ale moim głównym celem stworzenia takiego języka jest możliwość wprowadzenia programowania dla znacznie szerszej publiczności, w tym studentów K-12 i osób starszych, które mogą nie być biegły w języku angielskim. Na poziomie wprowadzającym prawdopodobnie nie muszą używać bibliotek zewnętrznych, a tworzenie zlokalizowanych opakowań dla niektórych małych (np. print) Nie zaszkodzi.
Hosam Aly,
1
Inną kwestią jest to, że wiele osób używa już swoich języków ojczystych do nazw klas i metod. Nie pomaga im to, że słowa kluczowe są w języku angielskim, ani nie robi różnicy dla innych ludzi, ponieważ słowa kluczowe nie są wystarczające do zrozumienia kodu nieanglojęzycznego. Niemniej jednak procesor wstępny może zawsze zastąpić słowa kluczowe z powrotem na angielski, a następnie na inny język, jeśli to konieczne.
Hosam Aly,