Jazyky, ktoré odhaľujú podrobnosti Keď väčšina ľudí začína s programovaním, priťahujú ich jazyky, ktoré uľahčujú prácu. Python, JavaScript a ďalšie jazyky na vysokej úrovni odstraňujú chaotické detaily správy pamäte, systémových volaní a interakcie hardvéru. Táto abstrakcia je výkonná – umožňuje začiatočníkom rýchlo vytvárať užitočné programy bez toho, aby sa zamotali do detailov implementácie. Jazyky, ktoré vás nútia konfrontovať sa s týmito detailmi, však majú významnú hodnotu. Jazyky ako Rust, C a Zig z vás nerobia len lepšieho programátora v týchto špecifických jazykoch – prehlbujú vaše pochopenie toho, ako počítače skutočne fungujú. Vďaka tomuto porozumeniu budete efektívnejší v každom jazyku, ktorý používate, dokonca aj v tých na vysokej úrovni. Aby sme to demonštrovali, zoberme si „jednoduchý“ koncept, ako je čítanie vstupu od používateľa a jeho uloženie do premennej, potom ukážme, ako by sa to dalo urobiť z jazykov vyššej úrovne na úroveň nižšej. Začneme tým najvyšším zo všetkých: Python name = input("What is your name?\n") print(name) #Ah, the classic I/O example Aké otázky tu môžu byť pre študenta? Pamätajte, že sa nesnažíme len vylúštiť kód, ale máme skutočne predstavu o tom, čo sa deje: Máme „premenné“, ktoré uchovávajú údaje. Premenné a pamäť: Máme dátové typy a reťazce sú jednoducho normálny text. Veľmi zvedavý študent by sa z tejto stopy mohol dozvedieť aj o iných typoch údajov. Dátové typy a pamäť: Môžeme volať funkcie s argumentmi a uložiť výsledky týchto funkcií do premennej. Volania funkcií: Python programy môžu byť spustené volaním interpreta a s programom (za predpokladu, že máme nainštalovaný Python; nebudem pykať za verzie, závislosti a inštaláciu Pythonu). To by mohlo viesť k objavu interpretovaných a kompilovaných jazykov. Runtime Environment Tieto nie sú zlé; Myslím, že najväčšie znalosti o počítačoch budú pochádzať z toho malého „\n“ v reťazci. Trocha preskúmania by viedlo k znalostiam o ASCII, UTF-8 a reprezentácii textu v počítači ako bajtov. Pre začiatočníka by to bolo asi , ale dalo by to o tom, ako ide text na 0 a 1. Je tu tiež malá lekcia o interpretoch a kompilátoroch, ale to by si vyžadovalo značné hĺbanie. priveľa predstavu Javascript/Typescript (Uzol) import readline from 'readline/promises'; const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); const name = await rl.question('What is your name?\n'); rl.close(); console.log(name); //Oh, js, so horribly wonderful in your ways Okrem predchádzajúcich poznatkov zhodnoťme, čo by zvedavý študent mohol pozorovať jednoduchým skúmaním tohto kódu: : Vidíme explicitné odkazy na Ich jednoduché preskúmanie by viedlo k prúdom súborov stdin a stdout v prostrediach založených na Unixe a možno dokonca aj k deskriptorom súborov a „všetko je súbor“ v systémoch Linux. Vstupné/výstupné toky štandardné a štandardné parametre. Videnie objektu by mohlo zvedavého človeka podnietiť k tomu, aby sa dozvedel o procesoch a nahliadol do procesu vykonávania moderných operačných systémov. Aj keď to nemusia úplne pochopiť, teraz majú Procesy: Process nápad. : a Promises oboznamujú študenta s tým, ako počítače zvládajú operácie, ktoré sa nedokončia okamžite, a možno aj s otázkou, prečo sa to jednoducho nevykonáva priamočiarym spôsobom (ako Python). Tieto motivujú k učeniu sa o: Asynchrónne I/O await Synchrónne a asynchrónne vykonávanie, neblokujúce I/O a možno aj súbežnosť Promises, Microtask Queue a Task Queue v Node, programovanie riadené udalosťami a jeho výhody. Vytvorenie a zatvorenie rozhrania vedie k otázke a získaniu pochopenia správy zdrojov, najmä pre dôležité zdroje, ako sú I/O toky. Vytvorenie rozhrania a správa zdrojov: ( , ): Tieto sa explicitne netýkajú hlbších konceptov, ale učia osvedčené postupy kontroly premenlivosti. Kľúčové slová deklarácie let const JS programy sa spúšťajú cez runtime, Node, Bun, Deno, atď. Úlohou runtime je poskytnúť (JS engine) ďalšie funkcie, aby sa z neho stal kompletný jazyk. Možno by sa dalo položiť otázku, presne tieto runtime poskytujú motoru V8, a to by viedlo k implementácii asynchrónnych I/O. Runtime prostredie: V8 čo Niektoré z nich, ako Promises a Queues, sú na prvý pohľad abstrakcie súvisiace s JS, ale ak si človek nakoniec nájde cestu do knižnice C, ktorá spracováva asynchrónne I/O pre Node.js – naučí sa niečo o I/O v operačných systémoch. Libuv – C-Sharp Console.WriteLine("What is your name?"); string? name = Console.ReadLine(); Console.WriteLine(name); //Surprise!! No public static void Main(string[] args) Zvyčajní podozriví z kódovania znakov sú tu, aj keď sú zakrytí a , okrem toho sa objavia dve dôležité veci: ReadLine WriteLine : Aj keď je odvodzovanie typu skvelou funkciou pre produktivitu, zastávam názor, že explicitné písanie typov zlepšuje proces učenia, najmä pre začiatočníkov. Tu by študent mohol získať svoju prvú skutočnú predstavu o rozložení pamäte, najmä keď skúmal dôvody pre explicitné špecifikovanie typov premenných. Patrí medzi ne rezervácia špecifických počtov bajtov pre určité premenné a chyby, ktoré sa vyskytnú, keď sa pokúsite vložiť 64 bajtov do 32 bajtov pamäte. Statické písanie a explicitné typy Učia sa, že je možné, že miesto v pamäti nemá platnú hodnotu, čo ďalej zlepšuje pohľad na pamäť. Typy s nulovou hodnotou: Naozaj zvedavý človek by sa začal pýtať — Prečo musíme explicitne uvádzať typy s nulovou hodnotou? Existujú nejaké konkrétne problémy, ktoré vyplývajú z toho, že v programoch sa s nulovými hodnotami zaobchádza ako s nenulovými hodnotami? To vedie k učeniu sa o pravidlách ochrany pamäte. Runtime .NET robí proces kompilácie zrejmejším tým, že núti študenta explicitne a potom kód. Common Language Runtime (CLR), Intermediate Language (IL) a JIT: zostaviť spustiť Nútenie používateľa skompilovať svoj kód mu umožňuje vidieť vygenerovaný IL. To nám umožňuje náš prvý pohľad do zostavy (v každom prípade pseudozostava), pokynov a registrov. Existuje tiež potenciál dozvedieť sa o Just-In-Time kompilácii CLR, ak študent načrie trochu ďalej pod kapotu. Aj keď tieto koncepty existujú v iných jazykoch, rozdiel je v tom, že ich odhalenie používateľovi im umožňuje okamžite preniknúť hlbšie a získať predstavu o tom, čo sa stane pri spustení kódu. skutočne Nakoniec, Nemáme nič, čo by sa týkalo streamov a správy zdrojov. I/O je tu viac abstraktné ako v JS. Golang Prepáčte, Gophers, ale nemôžem pokryť inak by bol tento článok príliš dlhý. všetko, Hrdza use std::io; fn main() { println!("What is your name?"); let mut name = String::new(); io::stdin() .read_line(&mut name) .expect("Failed to read line"); println!("{}", name); } //Almost a 1:1 from The Book Pre mierne zvedavého študenta, čo možno pochopiť o systémových konceptoch: : kľúčové slovo ukazuje, že premenné sú štandardne nemenné. Opäť kontrola nad premenlivosťou údajov pre všetky jej výhody. Explicitná mutabilita mut : ukazuje, že I/O môže zlyhať a núti zvážiť spracovanie chýb. Vo vyšších jazykoch sa to takmer považuje za samozrejmosť a študent môže pochopiť, že interakcia s fyzickými zariadeniami môže viesť k množstvu chýb, o ktorých by sa nemuselo ani zamýšľať, ak by neboli predložené. Skúste sa napríklad opýtať vývojára databázy, či sú disky dokonalé. Explicitné spracovanie chýb .expect() : explicitne odhaľuje interakciu s I/O zdrojmi na úrovni OS. Rovnako ako predtým to umožňuje hlbší ponor do konceptov I/O v operačnom systéme, pričom rozdiel je v tom, že veci sú oveľa holé ako v JS. Direct Stream Access io::stdin() : ukazuje naše prvé, aj keď pseudoexplicitné, stretnutie s haldou a zásobníkom, dvoma z najdôležitejších pojmov v pamäti. Aj keď to nie je príliš explicitné, poskytuje dostatok informácií, že zvedavý študent môže ľahko začať skúmať pamäť a klásť otázky ako: „Prečo potrebujeme rôzne pamäťové oblasti? "Čo je to hromada?" atď. Memory Allocation String::new() : odhaľuje náš prvý explicitný úvod do . Hoci každý jazyk doteraz používal pod kapotou referencie, ich vystavenie programátorom vpredu a v strede im umožňuje začať získavať hlbšie predstavy o rozložení pamäte. Učia sa, že môžeme použiť rovnaké údaje vo viacerých regiónoch jednoduchým použitím referencií spolu s výhodami a nebezpečenstvom takéhoto prístupu. Referencie a pôžičky &mut name ukazovateľov Výslovné vyžadovanie kroku zostavenia opäť spôsobí, že študent začne skúmať proces kompilácie, ale tentoraz má možnosť vidieť preskúmať až do bodu montážnych pokynov a trochu o procese vykonávania moderných CPU. Kompilátory, spustiteľné súbory a zostavenie: Aj keď vám vyhovuje abstrakcia na vysokej úrovni, experimentovanie s jedným malým prvkom v Ruste môže osvetliť celý svet správania systému, ktorý zostáva skrytý v iných jazykoch. Väčšina z nich nie je nová, rozdiel je v tom, že tu sú vystavení programátorovi, čo ich núti premýšľať a učiť sa o nich. Prináša to dodatočnú réžiu a ťažkosti, ale to je odmenené hlbším porozumením a následne mocou nad zdrojmi systému. Zig const std = @import("std"); pub fn main() !void { var debugAllocator = std.heap.DebugAllocator(.{}).init; defer std.debug.assert(debugAllocator.deinit() == .ok); const allocator = debugAllocator.allocator(); const stdout = std.io.getStdOut().writer(); const stdin = std.io.getStdIn().reader(); var name = std.ArrayList(u8).init(allocator); defer name.deinit(); try stdout.print("What is your name?\n", .{}); try stdin.streamUntilDelimiter(name.writer(), '\n', null); try stdout.print("{s}\n", .{name.items}); } //lol, the code block doesn't have support for Zig som diskutoval o tom, či zahrnúť alebo nezahrnúť haldy pridelené „rastúce“ reťazce alebo jednoducho mať veľmi veľký „statický“ reťazec pridelený zásobníkom, ale keďže som použil „rastúteľné“ reťazce pre každý ďalší príklad, tu sme. Jednoducho povedané, rastúci reťazec môže rásť s dodatočným vstupom, zatiaľ čo statický reťazec je pevný – jediný spôsob, ako pridať nové znaky, je vytvoriť nový s novým znakom. POZNÁMKA: Naozaj Ach chlapče, kde začneme? Ak by sa študent pozrel na tento kód, pravdepodobne by sa zľakol a utiekol, ale čo by sa mohol dozvedieť o systémových konceptoch, keď si preštuduje toto: Zig nám jasne hovorí, že keď potrebujeme získať pamäť z hromady, musíme deklarovať svoj zámer tak urobiť; nie je to pre nás také abstrahované ako v Rust. Tu je to odhalené. Aj keď to zvyšuje počiatočnú réžiu, vyzve vývojára, aby začal skúmať zásobník, haldu, dynamickú pamäť, systémové volania OS a prečo dokonca potrebujeme explicitne alokovať a uvoľniť pamäť. To ďalej posilňuje vývojárov pochopenie štruktúry pamäte. Alokátory a pamäť: Výslovné volaní na vyčistenie pamäte a kontroly úniku pamäte sú dobrými východiskovými bodmi na to, aby ste sa z prvej ruky dozvedeli o problémoch, ktoré vznikajú v dôsledku nesprávne spravovanej pamäte. V tejto chvíli je vývojár dostatočne vybavený na to, aby šiel v tejto téme naozaj do hĺbky. Čistenie a detekcia úniku: defer Reťazce sú jednoducho ukazovatele na pole hodnôt . Tým sa odstráni posledný kúsok abstrakcie medzi konceptom „reťazca“ na vysokej úrovni a myšlienkou „pola bajtov“ na nízkej úrovni. Reťazec, rezy a referencie: u8 Zviditeľnením týchto vecí vývojár opäť chápe, čo keď čítajú alebo zapisujú z I/O mimo programu. Priamy prístup k vstupno-výstupným tokom: sa stane, Volania I/O zariadení – a vo všeobecnosti systémové volania – môžu zlyhať. Vývojár to musí preskúmať a uvedomiť si to. Chyby I/O a spracovanie chýb: C a C++ Myslím, že ste pochopili pointu, ktorú tu chcem povedať; netreba biť mŕtveho koňa. Takže tu máte. Jednoduchá úloha vo viacerých jazykoch. Dúfam, že ste boli presvedčení o mojom názore. Predtým, ako pôjdeme, si však ujasnime niekoľko vecí: Takže, stačí to napísať a prepísať v hrdze? Nie, odpoveď je nie – len nie. Tieto argumenty uvádzam z pohľadu toho, kto sa chce dozvedieť viac o tom, ako fungujú počítače, a toho, kto potrebuje vytlačiť všetko z vášho hardvéru (môžete ísť aj na montáž, , ak chcete). ako na to chalani z FFMPEG Čo sa však stane, keď v záujme rýchlosti vývoja v pohode obetujete určitú efektivitu? Čo ak potrebujete napísať ľahký webový server s určitou logikou za deň alebo dva? Čo sa stane, keď ste nový vývojár, ktorý je tak zastrašený C++, že chce zahodiť kód? Existuje veľa situácií, pre ktoré je niečo ako Go, Elixir, Haskell alebo čokoľvek iné. Len vás žiadam, aby ste si potom našli čas a dozvedeli sa trochu o tom, čo sa skutočne deje; nemusíte byť hlupák na nízkej úrovni, ktorý dokáže písať asm aj v spánku, ale vedieť, čo sa deje s počítačmi, vám . A pomôže vám to prestať vnímať váš počítač ako čiernu skrinku. Tiež sľubujem, že si to užijete. pomôže napísať lepší a výkonnejší kód Porozprávajte sa so mnou na . Twitteri