JavaRush /Blog Java /Random-PL /Poziomy języków programowania
Marat Sadykov
Poziom 41

Poziomy języków programowania

Opublikowano w grupie Random-PL

Wstęp

Jakie są różne języki programowania? Jakie koncepcje są w nich zawarte? Jak się rozwinęli? W tym artykule przyjrzymy się rodzajom języków programowania w oparciu o tzw. poziomy – od kodów maszynowych (niski poziom, zbliżony do sprzętu komputerowego) po języki takie jak Java czy C# (wysoki poziom). Im mniej przekształceń przechodzi tekstowa lista programu na drodze zamiany na zbiór zer i jedynek, tym niższy jest poziom.
Poziomy języków programowania - 1
Następnie przyjrzymy się:
  1. Języki niskiego poziomu (kody maszynowe i asembler)
  2. Poziom średniozaawansowany (C, Fortran….)
  3. Wysoki poziom (C++, Java, Python, Ruby, JavaScript...)
Poziom charakteryzuje również stopień szczegółowości wykazu przyszłego programu, który musi być szczegółowy, aby możliwe było jego wdrożenie. Jak prosty jest ten proces dla człowieka? Poziomu języka nie należy uważać za jednoznaczny wyznacznik jego możliwości. Język programowania to narzędzie, które jest skuteczne w jednym obszarze i mniej przydatne w innych. Zarówno stolarz, jak i cieśla pracują z drewnem. Pierwsza posiada główne narzędzie – zestaw dłut, druga – siekierę. Jednak stolarz sprawi, że rzeźbiona szafka będzie bardziej elegancka, a cieśla szybciej zbuduje dom. Chociaż każdy z nich jest w stanie wykonać pracę drugiego, zrobią to znacznie mniej efektywnie. Różne dane w komputerze są reprezentowane jako zestawy zer i jedynek. Polecenia sterujące jego przetwarzaniem to same dane zawierające instrukcje określające lokalizację niezbędnych informacji i sposób modyfikacji.

Języki maszynowe (najniższy poziom)

Będziemy musieli dokonać krótkiej wizyty z obszaru oprogramowania do obszaru sprzętu. Spójrzmy na to w uproszczonej formie. Procesor jest głównym „mózgiem” komputera. Płyta główna, na której jest zainstalowany, zawiera kontrolery, które służą do interakcji z innymi urządzeniami za pośrednictwem magistrali (kanały danych do komunikacji).
Poziomy języków programowania - 2
Niektóre działają z dużą szybkością (czerwone strzałki): procesor pobiera polecenia z pamięci i manipuluje danymi, karta graficzna, zwłaszcza w grach 3D, zużywa ogromne ilości tekstur, kształtów, współrzędnych pikseli i innych obiektów, aby zbudować obraz na ekranie monitora . Inne (ze względu na ograniczenia w szybkości wymiany informacji) nie potrzebują tak wysokich wskaźników. Różne urządzenia wewnętrzne i zewnętrzne są połączone na schemacie za pomocą zielonych strzałek.

Wewnętrzny świat procesora

Wszystkie polecenia procesora pochodzą z pamięci i są wykonywane w formie binarnej. Format, liczba, podzbiór instrukcji zależy od jego architektury. Większość z nich jest ze sobą niezgodna i wyznaje odmienne ideologie. Również rodzaj polecenia silnie zależy od trybu (8/16/32... głębia bitowa) i źródła danych (pamięć, rejestr, stos...), z którym współpracuje procesor. To samo działanie może być reprezentowane przez różne instrukcje. Procesor posiada instrukcje dodawania dwóch operandów (ADD X, Y) i dodawania jednego do podanego (INC X). Dodanie trójki do operandu można wykonać za pomocą ADD X, 3 lub trzykrotnie wywołując INC X. W przypadku różnych procesorów nie można przewidzieć, która z tych metod będzie optymalna pod względem szybkości lub zajmowanej pamięci. Dla wygody informacje binarne są zapisywane w formie szesnastkowej. Rozważmy część znanego programu (język C, którego składnia jest podobna do Java)
int func() {
    int i = getData("7") ;
    return ++i;
   ...
}
Kod realizujący te same działania w formie sekwencji instrukcji dla procesora: ... 48 83 ec 08 bf bc 05 20 00 31 c0 e8 e8 fe ff ff 48 83 c4 08 83 c0 01 ... Tak w rzeczywistości wygląda język programowania niskiego poziomu dla procesora Intel. Fragment wywołujący metodę z argumentem i zwracający wynik zwiększony o jeden. Jest to język maszynowy (kod), który przekazywany jest bezpośrednio, bez przekształceń, procesorowi w celu wykonania. Plusy:
  • Jesteśmy w pełni panami sytuacji, mamy najszersze możliwości wykorzystania procesora i sprzętu komputerowego.
  • Mamy do dyspozycji wszelkie możliwości organizacji i optymalizacji kodu.
Wady:
  • Konieczne jest posiadanie szerokiej wiedzy na temat funkcjonowania procesorów i uwzględnienie dużej liczby czynników sprzętowych podczas wykonywania kodu.
  • Tworzenie programów nieco bardziej złożonych niż podany przykład prowadzi do gwałtownego wydłużenia czasu spędzanego na pisaniu kodu i jego debugowaniu.
  • Zależność od platformy: program stworzony dla jednego procesora zazwyczaj nie będzie działał na innych. Możliwe, że dla tego procesora w innych trybach pracy konieczna będzie edycja kodu.
Kody maszynowe były szeroko stosowane u początków komputerów, w epoce pionierów komputerów nie było innych metod programowania. Obecnie są sporadycznie wykorzystywane przez inżynierów zajmujących się mikroelektroniką przy opracowywaniu lub testowaniu niskopoziomowych procesorów.

Język asemblera (niski poziom)

W przeciwieństwie do komputera, ty i ja lepiej postrzegamy informacje w formie tekstowej/semantycznej niż w formie cyfrowej. Możesz z łatwością nazwać pięćdziesiąt nazw kontaktów na swoim smartfonie, ale jest mało prawdopodobne, że będziesz w stanie zapisać odpowiadające im numery telefonów na pamięć. Podobnie jest z programowaniem. Wspinamy się po drabinie typów, wykonując trzy podstawowe kroki:
  • Powiążmy jedną instrukcję symboliczną z grupami instrukcji procesora cyfrowego, które wykonują odpowiednie działania.
  • Podkreślmy osobno argumenty instrukcji procesora.
  • Wprowadźmy możliwość nazywania obszarów pamięci, zmiennych i lokalizacji poszczególnych poleceń.
Porównajmy fragmenty poprzedniego programu w kodzie maszynowym (w środku) i w języku asemblera (po prawej):
2004b0     48 83 ec 08      sub    $0x8,%rsp
2004b4     bf bc 05 20 00   mov    $0x2005bc,%edi
2004b9     31 c0            xor    %eax,%eax
2004bb     e8 e8 fe ff ff   callq  getData
2004c0     48 83 c4 08      add    $0x8,%rsp
2004c4     83 c0 01         add    $0x1,%eax
Jak widać, proces pisania programu został uproszczony: nie ma potrzeby korzystania z podręczników do generowania cyfrowych wartości poleceń, obliczania długości przejść, rozdzielania danych w pamięci pomiędzy komórkami i innych funkcji procesora. Pożądaną akcję opisujemy za pomocą zestawu symbolicznych poleceń i argumentów niezbędnych do logiki wykonania, a następnie program tłumaczący tłumaczy plik tekstowy na zbiór zer i jedynek zrozumiałych dla procesora. Plusy:
  • Uproszczono proces pisania i modyfikowania kodu.
  • Zachowana została kontrola nad wszystkimi zasobami sprzętowymi.
  • Stosunkowo łatwiej jest przenieść program na inne platformy, lecz wymagają one modyfikacji w zależności od kompatybilności sprzętowej.
Wady:
  • Język asemblera jest językiem programowania niskiego poziomu. Tworzenie nawet małych fragmentów kodu jest trudne. Ponadto należy wziąć pod uwagę specyfikę działania sprzętu.
  • Zależność od platformy.
Najpopularniejszy przykład demonstracyjny Java:
public static void main(String[] args) {
    System.out.println("Hello World!");
}
będzie wyglądać (składnia NASM, przy użyciu Windows API i kernel32.lib) w następujący sposób:
global _main
	extern  _GetStdHandle@4
	extern  _WriteFile@20
	extern  _ExitProcess@4

	section .text
_main:
	; DWORD  bytes;
	mov 	ebp, esp
	sub 	esp, 4

	; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE)
	push	-11
	call	_GetStdHandle@4
	mov 	ebx, eax

	; WriteFile( hstdOut, message, length(message), &bytes, 0);
    push	0
	lea 	eax, [ebp-4]
	push	eax
	push	(message_end - message)
	push	message
	push	ebx
	call	_WriteFile@20

	; ExitProcess(0)
	push	0
	call	_ExitProcess@4

	; never here
	hlt
message:
	db  	'Hello, World', 10
message_end:
Podobnie jak kody maszynowe, język asemblera jest częściej używany przez inżynierów i programistów systemów. Służy do pisania zależnych od sprzętu części jądra systemu operacyjnego, które są krytyczne czasowo lub krytyczne dla funkcji implementacji sterowników dla różnych urządzeń peryferyjnych. Ale ostatnio coraz rzadziej się do tego uciekają, ponieważ jego użycie znacznie ogranicza przenośność programów na inne platformy. Czasami stosują proces demontażu - tworzą listę asemblera programu z kodów cyfrowych, aby przeanalizować logikę wykonywania małych fragmentów. W rzadkich przypadkach, jeśli oryginalny kod wysokiego poziomu nie jest dostępny: analiza wirusów w celu ich zwalczania lub utrata kodu źródłowego. Za język asemblera uważa się język pierwszej/drugiej generacji (nie będziemy rozpatrywać oddzielnie pseudokodów sprzed pojawienia się asemblera i ich różnicy w stosunku do poleceń symbolicznych). Chciałbym podkreślić zastosowanie asemblera w Scenie Demo: fuzję sztuki, matematyki i kodowania niskiego poziomu, ucieleśniającą artystyczne pomysły ich twórców w postaci programów generujących klipy wideo z ograniczonymi zasobami. Często łączny rozmiar programu i pliku danych nie powinien przekraczać 256 bajtów (popularny jest również format 4/64 kilobajtów). Oto przykład programu o rozmiarze 4 KB:

Grupa C/Języki Fortran (poziom średniozaawansowany/wysoki)

Wraz z rozwojem możliwości technologii komputerowej ilość funkcjonalności i czas realizacji kodu w asemblerze przestały być zadowalające. Koszty pisania, testowania i utrzymywania programów rosły o rząd wielkości szybciej niż ich możliwości. Należało zmniejszyć wymagania stawiane programiście w zakresie znajomości funkcjonowania sprzętu, aby dać mu narzędzie, które pozwoliłoby mu pisać w językach bliskich ludzkiej logice. Przejdź na nowy poziom typów języków programowania. Zapewniono możliwość podziału na różne moduły z dalszym wywoływaniem sekwencyjnym (paradygmat programowania proceduralnego), udostępniono różne typy danych z możliwością ich konstruowania itp. Dodatkowo te działania przyniosły poprawę przenośności kodu na inne platformy, wygodniejszą organizację Praca w zespole. Jednym z pierwszych języków, który obsługiwał to wszystko, był Fortran, opracowany w latach 50. ubiegłego wieku . Możliwość tworzenia w formie tekstowej wraz z opisem logiki wykonania z wykorzystaniem pętli, rozgałęzień, podprogramów oraz operowania tablicami i prezentowania danych w postaci liczb rzeczywistych, całkowitych i zespolonych zachwyciła inżynierów i naukowców. W krótkim czasie powstały naukowe „ramy” i biblioteki. Wszystko to było konsekwencją faktu, że Fortran jest nadal aktualny, choć w wąskim środowisku naukowym, i rozwija się, ponieważ bagaż osiągnięć jest bardzo duży, sama biblioteka IMSL aktywnie rozwija się od 1970 r. (!), Jak czy pamiętasz wiele podobnych, odpowiednich programów? - weterani? Kolejną gałęzią rozwoju języków na tym poziomie jest C. Jeśli Fortran stał się narzędziem dla naukowców, to C powstał, aby pomóc programistom w tworzeniu oprogramowania aplikacyjnego: systemów operacyjnych, sterowników itp. Język pozwala na ręczne sterowanie alokacją pamięci i daje bezpośredni dostęp do zasobów sprzętowych. Programiści C muszą kontrolować byty niskiego poziomu, dlatego wielu uważa, że ​​C jest zaawansowanym językiem asemblera i często nazywany jest językiem „średniego poziomu”. Po wprowadzeniu do asemblera typowania danych, elementów programowania proceduralnego i modułowego, język C nadal pozostaje jednym z głównych języków programowania systemowego, czemu sprzyja także szybki rozwój mikroelektroniki w ostatnim czasie. Wszelkiego rodzaju gadżety, kontrolery, urządzenia sieciowe i inne wymagają sterowników, implementacji protokołów do współpracy i innego oprogramowania stosunkowo niskiego poziomu, aby wdrożyć interakcję ze sprzętem. Wszystko to składa się na dzisiejsze zapotrzebowanie na ten język. Zasady zorientowane obiektowo i funkcjonalne zostały dalej rozwinięte w postaci C++, C#, Java, czerpiąc wiele ze składni C. Zalety:
  • Uproszczenie procesu tworzenia kodu: wprowadzenie typów, podział na moduły, redukcja list programów.
  • Прозрачная логика заложенного алгоритма вследствие ухода от машинных kodов к более понятным для человека командам в семантически описательном стиле.
  • Переносимость. Стало достаточно перекомпLubровать текст программы для выполнения на другой платформе (возможно, с небольшой модификацией).
  • Скорость откомпLubрованных программ.
Минусы:
  • Отсутствие автоматического управления памятью и необходимость постоянного её контроля.
  • Отсутствие реализации концепций obiektно-ориентированного и функционального программирования.

Развитие языков высокого уровня

Języki programowania wysokiego poziomu w zakresie tworzenia oprogramowania coraz częściej zaczynają odchodzić od kodów maszynowych i wdrażać oprócz proceduralnych różne paradygmaty programowania. Należą do nich także implementacja zasad obiektowych. C++, Java, Python, JavaScript, Ruby... - gama języków tego typu jest dziś najbardziej popularna i poszukiwana. Dają większe możliwości wdrażania różnorodnego oprogramowania i nie da się jednoznacznie określić „specjalizacji” każdego z nich. Jednak popularność aplikacji w odpowiednich obszarach wynika z bibliotek/frameworków do pracy z nimi, na przykład: JavaScript - Frontend. Język został zaprojektowany do interakcji pomiędzy kliencką przeglądarką internetową a użytkownikiem i zdalnym serwerem. Najpopularniejsze biblioteki to Angular, React i VUE. Obecnie jest stosunkowo aktywnie wykorzystywany na serwerach WWW i innych (backend), szczególnie popularny jest Node.js. Ruby – zaplecze. Służy do tworzenia skryptów (plików serwisowych) oraz na serwerach WWW. Głównym frameworkiem jest Ruby On Rails. Python jest domeną naukową i inżynierską (obok domeny internetowej). Jest alternatywą dla standardowych pakietów obliczeniowych i matematycznych (Mathematica, Octave, MatLab...), ale ma typową semantykę języka i dużą liczbę bibliotek. Ma wielu fanów w dziedzinie systemów uczenia maszynowego, statystyki i sztucznej inteligencji. Często używane biblioteki to Django, numpy, pandas i tensorflow. C++ – Uniwersalny, ewolucyjny rozwój języka C. Zapewnia funkcjonalne i obiektowe możliwości programowania bez utraty możliwości interakcji ze sprzętem niskiego poziomu. Dzięki temu realizowana jest produktywność i elastyczność podczas tworzenia oprogramowania, ale cena również odpowiada: wysokiej barierze wejścia ze względu na złożoną specyfikację języka, konieczności niezależnej kontroli nad zasobami podczas wykonywania programu. Przy jego pomocy pisze się wiele programów jednoużytkownikowych i systemowych: moduły systemów operacyjnych (Windows, Symbian...), gry, edytory (Adobe Photoshop, Autodesk Maya...), bazy danych (MSSQL, Oracle...), odtwarzacze ( WinAmp...), itp. Należy zaznaczyć, że współczesne oprogramowanie jest produktem złożonym, przy tworzeniu którego wykorzystuje się kilka języków programowania jednocześnie i określenie stopnia udziału każdego z nich w procesie może być bardzo trudne. ogólny wynik.

Dalszy postęp

Ostatnio coraz większą popularnością cieszy się inny rodzaj programowania – funkcjonalny (dalszy rozwój poziomu językowego) . Oto inny rodzaj abstrakcji do obliczeń - funkcje, które przyjmują zbiór funkcji jako argumenty i zwracają inny. Rolę zmiennych pełnią te same funkcje (znane nam zmienne to po prostu wyrażenia stałe, podobnie jak final przed deklaracją typu w Javie). Sama funkcja jest zamknięta w swoim zakresie, wynik jej działania zależy jedynie od przekazanych argumentów. Wynikają z tego dwie niezwykłe właściwości:
  • Do testowania potrzebujemy jedynie argumentów funkcji (wynik pracy nie jest zależny od zmiennych zewnętrznych itp.).
  • Program w stylu funkcjonalnym jest w cudowny sposób gotowy na współbieżność: sekwencyjne wywołania funkcji mogą być wykonywane w sąsiednich wątkach (ponieważ nie mają na nie wpływu czynniki zewnętrzne) i nie wymagają blokad (to znaczy nie ma problemów z synchronizacją). Dobra zachęta do poświęcenia czasu temu tematowi, biorąc pod uwagę powszechne zastosowanie procesorów wielordzeniowych.
Próg wejścia jest jednak wyższy niż w przypadku OOP: dla efektywnego kodu konieczne jest zbudowanie programu opisującego algorytm wykonania w postaci funkcji. Ale także dla stylu czysto funkcjonalnego dobrze byłoby poznać podstawy logiki i teorii kategorii. Najpopularniejsze to Haskell, Scala, F#. Ale nie bójcie się, elementy programowania funkcjonalnego pojawiły się w Javie (a także w innych współczesnych językach trzeciej generacji) i można je łączyć z OOP. Wszystkie te szczegóły poznasz dokładniej podczas stażu online JavaRush. Dziedzina programowania logicznego (kolejny poziom języków) nie znalazła jeszcze szerokiego zastosowania praktycznego ze względu na małe zapotrzebowanie. Tworzenie programów wymaga znajomości podstaw matematyki dyskretnej, logiki predykatów, narzędzi ograniczających i innych gałęzi logiki matematycznej. Najpopularniejszym aktywnym językiem jest Prolog.

Wniosek

Obecnie najpopularniejszymi językami są OOP. Java od samego początku zawsze znajdowała się w czołówce, zwykle w pierwszej trójce najpopularniejszych języków. Oprócz OOP zawiera elementy programowania funkcjonalnego i umożliwia łączenie różnych stylów pisania programów. Wachlarz zastosowań języka Java jest bardzo szeroki – są to zadania biznesowe, implementacja serwerów WWW (backend), główny język do tworzenia aplikacji na Androida, wieloplatformowe środowiska programistyczne i miejsca pracy (IDE/AWM) oraz modelowanie i wiele więcej . Pozycja Java jest szczególnie silna w sektorze Enterprise – obszarze oprogramowania korporacyjnego, który wymaga wysokiej jakości i długotrwałego kodu oraz wdrożenia najbardziej złożonej logiki biznesowej.
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION