Sunteți în căutarea limbajului de programare perfect pentru a vă scrie aplicația proprie? și atâția experți v-au spus că nu există unul, doar anumite instrumente pentru anumite sarcini. Ba da, există, este imaginația dvs.! Trebuie doar să știți cum să o împărtășiți și celorlalți.
Paradigma tipurilor
Din punct de vedere istoric, limbajele de programare s-au împărțit în două categorii majore: un subset mai mic al limbajelor dinamice sau fără tip (de date) precum PHP, JavaScript, Python sau Ruby și unul mai mare de limbaje cu tip (de date) începând cu C, C++, Pascal, Fortran, Java, C#, Go sau Rust și ajungând la limbaje augmentate cu tip precum TypeScript sau Dart. Totuși, limbajele dinamice folosesc tipurile pentru manipularea datelor și chiar efectuează anumite verificări de tipuri la rulare, în timp ce limbajele cu tip sau statice ajung să ruleze de regulă sub formă binară, în care nu se efectuează implicit verificarea tipurilor pentru zonele de memorie reprezentând variabilele sau structurile de date ce au fost deja verificate în timpul compilării. Deci, tipurile de date sunt întotdeauna subînțelese atunci când scriem cod, dar nu atât de relevante pentru mașina ce execută codul. Aceasta deoarece tipul e un concept uman situat în vecinătatea unora similare precum categorie, fel, sortiment, clasă ș.a.m.d..
Deși limbajele statice au utilizat sintaxa mai strictă pentru a efectua o mai bună verificare a erorilor, compilare și optimizări (ahead-of-time), limbajele dinamice le-au ajuns din urmă ca facilități și performanță folosind tehnici precum compilare just-in-time și trasee de execuție. Pentru un set limitat de tipuri de date ale unei variabile din cod, majoritatea scenariilor de utilizare a acestora se invalidează de fapt la execuția programului.
Într-un limbaj de programare mai natural, denumirea variabilelor ar avea înțeles drept cuvinte, astfel încât împachetatorul/compilatorul s-ar putea informa dintr-un dicționar lingvistic uman pentru a efectua detectare suplimentară a tipurilor. Noi, ca oameni, profităm de celelalte informații senzoriale, de cunoștințe și de context pentru a infera și mai bine tipurile obiectelor. Un compilator, parser sau IDE deștepte pot utiliza interacțiunea/prompting-ul sau asistență AI pentru a finaliza identificarea tipurilor la dezvoltare.
Îndelungata dezbatere a exprimării sintactice a tipurilor de-a lungul codului poate deveni, până la urmă, doar o chestiune de a tasta sau a nu tasta.
O idee bună readusă la viață
După cum este descris în pagina proiectului TypeScript Lite, acest pachet Node.JS (TSLite) convertește un arbore de cod sursă JavaScript într-un arbore de cod sursă TypeScript.
Aceasta este posibil deoarece TSLite folosește una din cele mai simple forme de adnotare a tipurilor: notația prefix.
Ideea denumirii prefixate a identificatorilor, numită de asemenea notația maghiară, a fost adusă în urmă cu câteva decenii de către mari companii software pentru unele din platformele lor interne cum ar fi Microsoft MFC, Win32 API sau Borland OWL. Deoarece notația era folosită la nivel de platformă, iar companiile insistau pe construirea canonică a prefixelor necesare, dezvoltatorii s-au confruntat destul de repede în a se documenta cu un mare număr de elemente prefix consistând în principal din consoane, care i-au făcut să ironizeze despre învățarea de fapt a unei limbi străine, iar practica de a folosi denumirea cu prefixe s-a estompat.
Prin contrast cu implementarea originală, ce are totuși meritul unui bun început, notația prefix a TSLite are următoarele caracteristici cheie:
- Prefixele sunt definibile utilizator la nivelul unui proiect via fișier de configurare. E posibil de asemenea să se specifice prefixele la nivelul unui fișier via bloc de comentariu dedicat.
- Utilizatorul poate alege prefixe cu litere mici de orice lungime sau chiar cu potrivire cu un șablon regex. Aceste prefixe se aplică variabilelor cu tip de date prestabilit sau definit de utilizator, dar și unor variabile alese specific.
- În modulele CommonJS și ES, variabilele importate și exportate și funcțiile top-level pot și ar trebui exceptate de la denumirea cu prefix. TypeScript va infera tipurile acestora de la modulele importate și de la semnăturile funcțiilor. Nu se va aplica notația prefix la membrii unui obiect/clasă/map. Pentru aceste structuri, pot fi utilizate fișiere de definiții TS externe sau comentarii bloc structurale JSDoc.
Un exemplu al unui stub de aplicație convențională ExpressJS ce va fi convertit la TypeScript pe baza prefixelor variabilelor și a unui fișier de configurare, este afișat mai jos.
app.js
/* tslite-add * interface Request { app: any; } * interface Response { locals: any; render: Function; } */ const cookieParser = require('cookie-parser') const express = require('express') const httpErrors = require('http-errors') const logger = require('morgan') const path = require('path') const indexRouter = require('./routes/index') /// @ts-ignore const app = express() app.set('views', path.join(__dirname, 'views')) // view engine setup app.set('view engine', 'ejs') app.use(logger('dev')) app.use(express.json()) app.use(express.urlencoded({ extended: false })) app.use(cookieParser()) app.use(express.static(path.join(__dirname, 'public'))) app.use('/', indexRouter) // catch 404 and forward to error handler app.use((req, res, next) => { next(httpErrors(404)) }) // error handler app.use((err, req, res, next) => { // set locals, only providing error in development res.locals.message = err.message res.locals.error = req.app.get('env') === 'development' ? err : {} // render the error page /// @ts-ignore res.status(err.status || 500) res.render('error') }) module.exports = app
app.ts
interface Request { app: any; } interface Response { locals: any; render: Function; } const cookieParser = require('cookie-parser') const express = require('express') const httpErrors = require('http-errors') const logger = require('morgan') const path = require('path') const indexRouter = require('./routes/index') /// @ts-ignore const app = express() app.set('views', path.join(__dirname, 'views')) // view engine setup app.set('view engine', 'ejs') app.use(logger('dev')) app.use(express.json()) app.use(express.urlencoded({ extended: false })) app.use(cookieParser()) app.use(express.static(path.join(__dirname, 'public'))) app.use('/', indexRouter) // catch 404 and forward to error handler app.use((req: Request, res: Response, next: Function) => { next(httpErrors(404)) }) // error handler app.use((err: any, req: Request, res: Response, next: Function) => { // set locals, only providing error in development res.locals.message = err.message res.locals.error = req.app.get('env') === 'development' ? err : {} // render the error page /// @ts-ignore res.status(err.status || 500) res.render('error') }) module.exports = app
tslite.json
{ "input": ["express-app", "sample.js"], "output": "../src-ts", "matcher": [ "/\\.js(x?)$/i", ".ts$1" ], "prefixes": { "a": "any[]", "b": "boolean", "f": "Function", "n": "number", "o": "any", "s": "string", "$e[0-9]*": "any", "$[i-nx-z][0-9]*": "number", "req": "Request", "res": "Response", "$next": "Function", "$err": "any" } }
tsconfig.json
{ "compilerOptions": { "outDir": "dist", "strictNullChecks": false, "target": "es2016", "module": "commonjs", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true } }
Fiind generat de un utilitar automat (yeoman), codul JS este păstrat nemodificat, dar puteți aplica notația prefix cu ușurință la toate variabilele dorite și vedea imediat adnotările suplimentare TS rezultate.
Deși pachetul TSLite e o aplicație consolă Node.JS, poate fi rulat uniform pe proiecte de cod mobile, browser, server sau pe orice proiect ES5/ES6. Un flux de lucru tipic ce poate fi ales este: scrieți mai întâi codul dvs. ES6 și verificați-l cu ESLint, apoi convertiți codul folosind TSLite și verificați-l cu TSC.
Deoarece acest set de unelte vă permite să scrieți cod JavaScript robust ce va fi convertit într-un singur pas în orice dialect al adnotării TS, ca de exemplu AssemblyScript, puteți folosi notația prefix pentru a transforma automat spre un cod sursă cu tipuri/static.
Stenografie
Oamenii au folosit metoda notației prescurtate, denumită și stenografie, încă din antichitatea greacă clasică(cca. 400 î.e.n.), pentru a înregistra mesajele vorbite în scris cu viteză comparabilă cu cea a vorbitorului. Despărțindu-se de erele greacă și romană, stenografia a cunoscut o evoluție majoră în secolele al 18-lea și al 19-lea, cu forme de notație prescurtată bazate pe figuri geometrice (cercuri, linii, punte) și mai apoi pe simboluri pentru foneme (sunetele rostite). Cea din urmă s-a standardizat și, în câteva decenii, a fost adoptată în mai bine de 16 limbi din Europa, America și Asia. În același timp, stenografia, ortografia (a semnelor de punctuație și a abrevierilor) și notația simbolică din științe au împrumutat puternic una de la alta, maturizându-se și devenind concomitent metodologii standard. Ceea ce a început ca necesitate de viteză în scris, a devenit o abordare universală de a transmite informație relevantă, concisă și precisă pentru oamenii din întreaga lume.
Un secol mai târziu, creatorii limbajelor de programare de generația a 3-a s-au inspirat din principiile notațiilor prescurtată și simbolică, construind prima sintaxă cu aspect uman pentru ceea ce încă era perceput, la cel moment, ca un ambalaj mai prietenos în jurul logicii computaționale și a seturilor de instrucțiuni cod-mașină. Datorită universalității lor, unele dintre aceste limbaje au devenit coloana vertebrală a programării moderne, fiind adoptate în orice colț al lumii, unde au popularizat un avans tehnologic comun și slang-ul pe care îl numim azi ” “Engleză IT “.
Este de presupus că uneltele de codare rezolvă în special probleme tehnice, ele constituie totuși, pretutindeni, și o modalitate puternică de a colabora și de a comunica, la fel cum notațiile prescurtată și simbolică erau deja cu un secol înainte de era digitală.
Limbajul Script
Având în vedere argumentele anterioare, se poate spune că limbajul de programare de scop general al viitorului apropiat va avea următoarele caracteristici cheie:
- Provine dintr-o abordare centrată pe om bazată pe matematică și fizică spre deosebire de cea bazată pe setul de instrucțiuni ale mașinii. Algoritmica, uneltele și AI-ul curente sunt capabile să traducă de la sintaxa exprimării umane la logica de calcul. Este de așteptat ca programarea viitoare a majorității sistemelor se va ocupa doar de problema de business, permițând în același timp un spectru complet de input-uri umane în afară de scriere.
- Folosește cuvinte scurte, abrevieri (ale englezei internaționale simplificate de ex.) și simboluri pentru cuvintele cheie și operatori, păstrând un vocabular al limbajului ușor de înțeles, aderând totodată la principiul notației prescurtate de a scrie concis și precis. Codul e scris într-un fel de limbaj universal, dar se citește verbal în limba naturală a cititorului (asemănător cum este citit pseudo-codul în prezent).
- țintește runtime-urile atât compilat cât și interpretat. Codul introdus original de către om este considerat sursa de adevăr. Pentru oricare din ținte, poate fi generat un cod augmentat în mod automat sau cu ajutorul utilizatorului. Codul augmentat e legat de segmente sau unități logice (de factor a câteva linii) ale codului original. Modificarea unui segment al codului original invalidează fragmentul corespunzător din codul augmentat, care va trebui să fie regenerat în funcție de cerințele țintei.
- Are un framework pentru controlul structurilor de date și a fluxului programului numit constrângerile programului. Acest framework al constrângerilor programului descrie și configurează următoarele: tipurile datelor, forma obiectelor (structura), validarea câmpurilor de date, ierarhia erorilor, prioritatea modulelor (secvența), configurarea concurenței etc.. este secundar la și se aplică imediat după codul original, afectând astfel orice cod augmentat. Este disponibil pentru a fi folosit și la rulare, luând parte efectiv în programul ce rulează.
Software-ul ce permite programarea cu acest limbaj are un set modern de unelte dezvoltator, incluzând: lint-are, compilare, audit de cod și generare de teste, împachetare, emularea rulării (sandbox). Pentru toate etapele în care se generează o anume formă de cod sau de program, există trasabilitate, iar factorul uman poate interveni dacă este necesar.
Limbajul, pe care îl vom denumi simplu “Script”, facilitează utilizarea structurilor de date high-order și a algoritmilor (ca în C++ STL), wrapper-ere pentru servicii asincrone și web, diverse instrumente pentru procesarea datelor și AI, prin includerea codului acestora în biblioteca utilizator standard.
Multe dintre limbajele de scop general de astăzi au obținut optimizările interne pentru faza de compilare sau just-in-time, biblioteci elegante și disponibile gratuit pentru domenii de interes comun și o bună ergonomie pentru dezvoltatorul ce urmărește rezolvarea problemelor complexe. Învățarea de bază a acestora a devenit trivială datorită generării AI a codului și interșanjabilitatea lor evidentă datorită capabilităților excelente ale transpiler-elor de cod de azi. În loc de a învăța zece dialecte sau zece moduri de a utiliza un instrument avansat care este platforma noastră de soluții software, o persoană se poate concentra la a stăpâni limbajul de scop general ce țintește toate runtime-urile comune fie compilate sau interpretate și oferă setări flexibile de optimizare, biblioteci specializate de business și tehnologie și un ecosistem universal gata să implementeze orice demers creativ.
Un cerc complet
Imaginați-vă că pe tastatura computerului dvs. aveți și două rânduri suplimentare de taste ce sunt figuri geometrice regulate și simboluri cunoscute ca cele pe care le utilizăm în mod curent. Oricare dintre aceste douăzeci de taste simbol inițiază și finalizează o secvență de maxim trei apăsări de taste ce vor deveni, în final, un simbol geometric. Prima apăsare va desena figura tastată în partea de jos la poziția de tastare, a doua apăsare va desena figura sau simbolul tastat în partea de sus (poate cu o ușoară suprapunere temporară), iar a treia apăsare se va desena ca superscript sau subscript (printr-o tastă modificator) în cadrul aceluiași simbol geometric ce va lua locul unui singur caracter. Încă de la prima apăsare, o listă de tip popup va apărea lângă poziția de tastare conținând simboluri geometrice finale sortate după similaritate cu secvența de tastare. Aceasta este o listă cu selecție individuală în care fiecare element este un simbol geometric urmat de un cuvânt în limba nativă sau preferată a utilizatorului, dar cu același înțeles global când e tradus. Selecția din listă se mută sau se rafinează pe măsură ce tastați secvența sau prin navigare utilizator (taste săgeți, mouse, atingere, dictare etc.). secvența se termină fie la a treia tastă apăsată, fie la apăsarea unei taste terminale (de ex. Enter) sau o tastă caracter//delimitator alta decât cele douăzeci, sau alegând un element din listă.
Simbolul final nu este o juxtapunere directă a figurilor tastate, ci este mai degrabă indicat de succesiunea lor și de compunerea acestora, arătând și comportându-se de fapt ca un font truetype. Exemple ale unor astfel de simboluri finale pot fi: un pătrat urmat de un triunghi așezat produce simbolul ‘casă ‘, un pătrat urmat de un triunghi cu capul în jos produce simbolul ‘arbore ‘, o linie de subliniere urmată de un cerc produce simbolul ‘răsărit ‘, o linie de subliniere urmată de un cerc și apoi de un asterisc produce simbolul ‘apus ‘.
Scriptul simbolic introdus va purta de asemenea un transcript în cuvinte într-o limbă vorbită implicită (ex. engleza), care se traduce cuvânt-la-cuvânt la cuvintele alese de utilizatorul care a tastat.
Folosită la scrierea codului, această metodă de tastare permite utilizarea simbolurilor geometrice peste tot unde folosim cuvinte pentru denumiri precum la variabile, funcții, clase, nume membri etc.. aceasta poate funcționa la codul propriu-zis în timp ce este păstrat formatul text pentru schimbul de date precum JSON sau XML.
Reamintiți-vă că scrierea latină provine în ordine din greacă, feniciană, arameică și, în ultimă instanță, din hieroglifele egiptene, iar schițele abstracte preced scrisul ca și concept al minții umane. De asemenea, diverse ilustrări SF prezintă un grup de figuri sau simboluri geometrice ca fiind o secvență de comandă pentru activarea unor tehnologii ale viitorului îndepărtat.
Se spune că forma perfectă din univers este cercul, de aceea și utilizarea sa constantă în arte, frumusețe și chiar și în științe. planetele din fiecare câmp gravitațional al stelei acestora zboară prin spațiu cu pierdere minimă de energie pe traiectorii închise și aproape circulare. Chiar și minusculul electron se rotește mereu în jurul nucleului atomului înăuntrul unei fâșii închise numită nivel energetic.
Se pare că traseul sau calea circulară e una dintre legile fundamentale ale universului. Unii oameni spun că însăși istoria umană tinde să se repete în cicluri după câteva sute sau mii de ani.
Dar unii dintre noi totuși au observat că planetele când își închid traiectoria nu se întorc în același punct din univers deoarece stelele și întregi galaxii au propriile trasee de călătorie. și minusculul electron are tendința de a sări de pe un nivel energetic pe altul, ba chiar să părăsească atomul. Dacă desenați un cerc în nisip, nu se va închide în același punct din spațiu deoarece planeta s-a rotit între timp. Cercurile ființelor vii auto-evoluează în spirale.
Am aflat așadar că există o a doua lege fundamentală în univers, cel puțin la fel de importantă ca și prima, numită evoluție.
Pentru acei dintre noi ce prețuiesc cunoașterea umană, nu trebuie să fie loc de a ne fi frică de căi închise, sau că istoria s-ar putea repeta.