Iconoclastul Oberon/F

Existenta unei crize a industriei de software începe să devină o evidentă din ce în ce mai greu de negat. Semnale de alarmă au fost trase atît de domeniul tehnologic (produsele comerciale sînt tot mai nesigure iar dezvoltarea de aplicatii tot mai dificilă si costisitoare) cît si de cel comercial (acapararea pietei de un număr restrîns de producători, avînd drept consecintă instituirea unui monopol si scăderea concurentei). Cauzele acestei crize se află în cresterea exponentială a complexitătii aplicatiilor pînă dincolo de capacitatea instrumentelor si metodologiilor ingineriei software de a le controla. Impunerea unor paradigme informationale noi (cum ar fi interfetele grafice si arhitecturile client/server) nu a fost dublată de impunerea unor standarde unanim acceptate privind interactiunea între diverse programe si aplicatii.

Din perspectivă istorică, aceasta este a doua criză majoră a acestei tinere industrii. Prima a fost cea din 1968, solutionată printr-un efort comun al comunitătii informatice, efort orientat spre domeniul limbajelor de programare. Solutiile formulate în această perioadă s-au cristalizat în paradigme larg acceptate (programare structurată, programare modulară, programare orientată pe obiecte) care au rezistat în timp si au propulsat industria de software pînă la stadiul actual.

Problema actuală însă nu mai poate fi rezolvată doar prin aplicarea riguroasă a acestor paradigme. Modelul industriilor mature este cel care poate indica cel mai clar calea: construirea aplicatiilor software prin asamblarea de componente capabile să conlucreze.

Orientarea pe documente, si nu pe aplicatii, este un corolar imediat al posibilitătii de a utiliza componente software. Această tendintă este evidentiată si de disputa (atît tehnologică cît si comercială) pentru impunerea unor standarde, între care OLE 2 (Microsoft) si OpenDoc (IBM/Apple/Motorola) sînt capete de afis. Dezvoltarea de aplicatii care să se conformeze acestor specificatii ridică însă si mai mult nivelul de complexitate al dezvoltării, riscînd astfel să compromită chiar scopul final al acestor standarde.

O solutie surprinzătoare prin simplitate, elegantă si eficacitate o reprezintă Oberon/F, primul mediu de lucru (framework) pentru componente, multiplatformă, extensibil si compatibil cu ambele standarde rivale.

Istoria

În 1985, la ETH (Institutul Federal de Tehnologie din Zurich, Elvetia), a fost lansat un proiect care consta din realizarea unui sistem de operare pentru statiile de lucru Ceres. Proiectul, condus de profesorii Niklaus Wirth (inventatorul limbajelor Pascal si Modula-2) si Jurg Gutknecht, a fost botezat Oberon si a pornit de la două idei fundamentale: simplitate si extensibilitate. Pentru atingerea acestor obiective au fost abandonate toate modelele existente, sistemul software fiind conceput din temelie pe baze noi. Un prim pas a fost dezvoltarea unui limbaj de programare care să ofere simplitatea si puterea necesară pentru realizarea sistemului de operare. Limbajul s-a numit la rîndul său Oberon, si s-a dovedit mai simplu decît Pascal si mai puternic decît Modula-2, preluînd de la acestea ideile valoroase legate de structură si modularitate, la care s-au adăugat trăsăturile obiectuale fundamentale.

Rezultatul a fost un sistem de operare modern si performant, bogat în functionalitate, revolutionar în conceptie si care încăpea în mai putin de 200 Kb de memorie! Utilizarea curentă a sistemului pe statii Ceres pentru aplicatii diverse, de la birotică la CAD, a încurajat dezvoltarea si perfectionarea sistemului. A urmat o revizie a limbajului (Oberon-2) si portări ale sistemului pe diverse platforme, s-au scris cărti, sistemul a devenit tot mai cunoscut si apreciat în mediile academice si de cercetare, datorită simplitătii, eficientei si înaltului nivel de integrare. (vezi si prezentarea "Oberon" din OPEN-TI nr. 2, 1994).

În ciuda ecoului favorabil obtinut, răspîndirea sistemului a fost împiedicată de incompatibilitatea flagrantă cu sistemele comerciale. Pentru a trece de acest handicap, singura variantă posibilă rămînea realizarea unei implementări reduse, care să utilizeze suportul sistemelor de operare si al interfetelor grafice comerciale cele mai populare.

În 1992 a fost înfiintată compania Oberon microsystems, Inc. avînd ca obiectiv fructificarea în produse comerciale a experientei si experimentelor de la ETH, în special proiectul Oberon. Implementarea limbajului Oberon-2 realizată aici, numită Oberon/L, a fost utilizată apoi pentru implementarea unui mediu de lucru extensibil bazat pe filozofia componentelor care a stat la baza sistemului Oberon. Rezultatul, numit Oberon/F si apărut în 1994 simultan pentru Windows (32 de biti) si Macintosh. În 1995 a apărut versiunea 1.1, care a adăugat cîteva elemente noi, urmînd ca următoarea versiune, prevăzută pentru prima parte a acestui an, să aducă suportul nativ pentru OLE si OpenDoc (simultan!). O versiune Unix, bazată pe X-Window, este la rîndul ei în pregătire.

Mediu extensibil

De regulă, proiectantul de software se foloseste de un mediu de dezvoltare, care cuprinde în mod uzual un editor de cod sursă, un compilator, un depanator interactiv, un editor de legături (linker) si niste instrumente CASE. Dintre acestea din urmă, au devenit locuri comune instrumentele vizuale pentru construirea interfetei si, tot mai adesea, instrumente pentru modelarea structurilor de date. Pentru realizarea aplicatiilor, proiectantul foloseste adesea biblioteci (realizate "în casă" sau cumpărate) cuprinzînd subrutine sau, în cazul limbajelor orientate pe obiecte, ierarhii de clase. Proiectantii produc cu ajutorul acestui instrumentar aplicatii finite, cu functionalitate bine definită si, eventual, biblioteci de rutine statice (utilizabile la realizarea altor programe) sau dinamice (utilizate la executia altor programe).

Mediul de lucru Oberon/F (framework) cuprinde si el un subsistem de dezvoltare, compus în principiu din aceleasi elemente. În plus însă Oberon/F mai cuprinde un nucleu (core), un subsistem de text si un subsistem de forme. Ultimele două subsisteme permit lucrul cu documente compuse, fiind folosite si în cadrul subsistemului de dezvoltare, pentru editarea codului sursă si a interfetei (dar nu numai).

Nucleul Oberon/F cuprinde un executiv (run-time) pentru module Oberon, un încărcător (loader) cu verificarea versiunilor, un colector de memorie reziduală (garbage-collector), o bibliotecă de clase sub forma unei colectii de module Oberon.

Prezenta unui (run-time) poate să pară stranie si cu sigurantă va duce cu gîndul pe multi cititori la ideea că este vorba de o interpretare de cod. Nu este asa: codul realizat de compilator este cod nativ pe 32 de biti. Explicatia prezentei acestui nucleu este cheia extensibilitătii întregului sistem.

Un framework, în cazul de fată Oberon/F, poate fi considerat o aplicatie nefinalizată (sau, mai bine zis, nesfîrsită). El oferă un cadru general cuprinzînd multe elemente de uz general (cum ar fi subsistemul de text) dar care poate fi îmbogătit si specializat cu noi componente. Dacă am nevoie ca în documentele mele să se poată utiliza tabele de calcul, voi implementa o astfel de componentă sau, mai probabil, o voi cumpăra. Ceea ce este esential este faptul că nu voi fi nevoit să recompilez întregul ansamblu pentru a obtine interactivitatea cu noua componentă. Este suficient să obtin codul executabil, care va fi încărcat si lansat în executie atunci cînd în document există un element care este o tabelă de calcul.

Spre deosebire de situatia clasică (biblioteca de rutine) în care codul nou (al aplicatiei) apelează codul vechi (al sistemului de operare, de pildă), în cazul unui astfel de mediu de lucru apare si situatia în care codul vechi (în cazul de fată framework-ul) apelează codul nou. De pildă subsistemul de text, parcurgînd caracterele unui document, întîlneste un element care nu este caracter (de pildă este o tabelă de calcul), situatie în care trebuie să apeleze componenta corespunzătoare. Siguranta sistemului în ansamblu nu poate fi asigurată prin mijloacele proprii ale unui limbaj de programare, deoarece nu se poate face nici o supozitie despre modul în care proiectantul respectivei componente a implementat, de pildă, gestionarea memoriei. Deoarece ideea componentelor software se bazează tocmai pe legarea tîrzie (late binding) a componentelor (adică la momentul executiei), este limpede că un mediu bazat pe componente trebuie să se bazeze pe un nucleu care să sprijine executia în sigurantă a codului.

Executivul verifică, de pildă, compatibilitatea tipurilor pentru a evita utilizarea incorectă a interfetei între module. Un apel incorect conduce la o eroare locală, care nu afectează restul sistemului. Dacă, de exemplu, un document contine un element de un tip necunoscut sistemului, el este considerat un alien si este ignorat. Cu toate acestea el va supravietui operatiunilor de copiere, salvare, restaurare, etc. De îndată ce codul componentei corespunzătoare este adăugat sistemului, elementul respectiv "prinde viată".

Limbajul

Oberon/L, limbajul implementat în Oberon/F, respectă specificatiile Oberon-2 elaborate de ETH. Pentru orice programator familiarizat cu Pascal sau Modula-2, învătarea noului limbaj este o chestiune de 2-3 zile. Păstrează structura si expresivitatea Pascal-ului, dar este modular si obiectual.

Singura unitate de compilare este modulul. Nu există notiunea de program sau aplicatie. Rolul unui modul este de a limita vizibilitatea elementelor de program definite (constante, tipuri, variabile, proceduri). Un modul are o interfată formată din acele elemente de program care au fost explicit declarate publice (exportate, în terminologie Oberon). Orice modul poate să folosească (să importe) interfata altui modul. Oberon/F nu este altceva decît o ierarhie de module.

Tipizarea este strictă, în ideea de a depista erorile în fazele timpurii ale dezvoltării (de preferintă la compilare). Verificarea statică a compatibilitătii tipurilor este dublată de o verificare dinamică (la momentul executiei) pentru modulele care nu au fost disponibile la momentul compilării si pentru tipurile dinamice.

Oberon/L este orientat pe obiecte, cu toate că jargonul specific a fost evitat. Practic există doar cîteva elemente care duc limbajul în zona OO. Tipul articol (record) poate fi extins. O extensie a unui tip articol mosteneste toate cîmpurile părintilor săi. Cîmpurile unui articol pot fi si de tip procedural. Există posibilitatea de a lega o anumită procedură de un anumit tip (type-bound procedure). O astfel de procedură (numită uneori, în ciuda dorintei profesorului Wirth, metodă) poate fi aplicată doar variabilelor apartinînd tipului respectiv sau tipurilor care-l extind. Polimorfismul este realizat prin supraîncărcarea metodelor sau prin comunicarea prin mesaje (De remarcat că procedurile tipizate au fost introduse abia în Oberon-2. Sistemul de operare Oberon a fost realizat implementînd polimorfismul exclusiv prin intermediul mesajelor).

Nimic nu împiedică implementarea unor alte compilatoare sau interpretoare de cod în Oberon/F. Înainte ca cineva să pornească un astfel de demers este bine să reflecteze asupra faptului că limbajul Oberon este suficient de simplu pentru a fi folosit pentru scripting si suficient de puternic pentru a permite scrierea unui întreg sistem de operare.

Fete si interfete

Un principiu urmărit cu consecventă în realizarea lui Oberon/F a fost separarea între interfata cu utilizatorul si implementarea functionalitătii componentelor. Aceasta permite mediului si componentelor Oberon/F să devină în mare măsură independente de modelul interfetei gazdă. Un cod sursă "curat" (deci care nu recurge API-ul sistemului gazdă) va prelua în mod firesc look and feel-ul specific interfetei sistemului gazdă, oferind exact aceeasi functionalitate. În acest sens este de remarcat că Oberon/F abstractizează în mare măsură interfata (de pildă nu se face nici o prezumtie despre sistemul de ferestre ce va fi folosit) si sistemul de operare (de pildă nu se presupune nici măcar că sistemul de fisiere este arborescent).

Separarea interfetei este încurajată si în dezvoltarea de noi componente. Formele (folosite ca machete de culegere sau casete de dialog) nu sînt altceva decît documente Oberon/F obisnuite, care pot fi deschise, editate si utilizate după ce în prealabil au fost puse în corespondentă cu o variabilă (de regulă un articol). Dacă tipul variabilei este descendent al unui tip furnizat de nucleu (Dialog.Interactor) controlul programului asupra formei poate fi total. Niciodată realizarea unui dialog Windows nu a fost mai simplă si mai naturală.

Sistemul de meniuri este perfect configurabil, atît interactiv cît si programatic. Orice editor îsi poate instala în mod dinamic propriile elemente de meniu.

Absolut tot ce se poate face interactiv în Oberon/F se poate face si prin program, deoarece nici una dintre functionalitătile implementate într-un modul nu poate fi accesibil decît prin interfata publică a respectivului modul. În felul acesta, orice modul dispune si de o interfată de programare (API). Această interfată poate fi obtinută în orice moment, pentru orice modul.

În vederea asigurării extensibilitătii si sigurantei sistemului, la proiectarea interfetelor Oberon/F (către utilizator si către programator) trebuie avute în vedere următoarele principii, formulate si urmărite si în constructia framework-ului:

Porturi si fisiere

Ierarhia de module care constituie Oberon/F formează un sistem de abstractiuni construit într-o manieră sistematică. Fără pretentia de a epuiza complexitatea sistemului, prezentarea cîtorva notiuni mai importante poate fi utilă în întelegerea principiilor functionării mediului.

Carrier (portbagaj) este un un container de date exterior sistemului Oberon/F, cum ar fi o matrice de pixeli (cazul ecranului si al imprimatei, numite în general porturi) sau un sir de octeti (cazul fisierelor). Pot exista simultan mai multe căi de acces la datele unui carrier. O astfel de cale se cheamă rider. Un rider oferă o interfată de nivel jos (numită bottleneck interface), furnizînd operatii elementare de intrare/iesire. Implementarea unui rider este dependentă de implementarea carrier-ului corespunzător.

La un nivel superior de abstractizare se află asa-numitii mappers. Fiecare mapper se leagă de carrier prin intermediul unui rider. Spre deosebire de un rider, un mapper nu stie nimic despre implementarea carrier-ului corespunzător, ceea ce înseamnă că poate fi extins în mod independent.

În cazul unui port (să considerăm e-cranul), mapper-ii se cheamă frames (cadre). Spre deosebire de cazul rider-elor, care folosesc sistemul de coordonate al portului (cu originea în coltul din stînga-sus) si exprimă coordonatele în unităti specifice perifericului (pixeli), frame-urile dispun fiecare de un sistem propriu de coordonate si exprimă coordonatele în unităti de măsură universale.

Fisierele au o utilizare foarte limitată în Oberon/F. Sînt considerate simple siruri de octeti, accesibile prin două tipuri de rider, numiti reader si respectiv writer, care furnizează operatiile elementare. Pentru un fisier pot fi deschise simultan mai multe reader-e si/sau writter-e. Facilitătile oferite pot fi folosite pentru implementarea unor convertoare destinate importului de date din vechile aplicatii sau pentru implementarea unor mecanisme simple de baze de date.

Paradigma MVC

Pentru interactiunea cu utilizatorul, Oberon/F se bazează pe o metodă numită MVC paradigm, dezvoltată pentru SmallTalk la Xerox PARC. Initialele semnifică cele trei tipuri de obiecte folosite: M - Models, V - Views, C - Controllers.

Un model este o structură persistentă ce păstrează date care trebuie prezentate vizual, de pildă un text (secventă de caractere plus informatii despre fonturi) sau un desen (un set de obiecte grafice plus informatii despre trasarea liniilor: culoare, grosime, etc). Modelul reprezintă o extensie a tipului Store din modulul Stores, tipul de bază pentru toate tipurile persistente. De la acesta mosteneste posibilitatea de a se externaliza într-un fisier pe disc si respectiv de a se internaliza din acest fisier, precum si reader-e si writer-e reprezentînd mapper-e de fisier care implementează codificarea binară a valorilor manipulate de Oberon/L, cum ar fi caractere, numere, seturi si chiar alte structuri persistente.

Un View reprezintă o posibilitate de prezentare vizuală a unui model. Un view proiectează continutul modelului într-o zonă dreptunghiulară de afisare, folosind cadre (frames) ca mapper-e către porturi (ecran sau imprimantă). Tot cadrele reprezintă canale de intrare pentru semnalele generate de tastatură sau mouse, ofe-rind astfel view-urilor posibilitatea de a implementa o interactiune simplă cu utilizatorul.

Un acelasi model poate fi prezentat (chiar simultan) de mai multe view-uri diferite. De pildă un sir de numere poate fi reprezentat fie ca o tabelă, fie ca un grafic (de pildă bar chart).

Cu toate că si view-ul poate realiza interactiunea cu utilizatorul, în cazul unor aplicatii interactive complexe această sarcină este delegată unui obiect specializat numit Controller. Acesta poate la rîndul lui să delege realizarea operatiilor unor alte obiecte numite operations, care implementează operatii reversibile asupra unui model sau a unui view, oferind facilitatea nelimitată (decît de memoria disponibilă) de Undo/Redo.

Mesaje

Mesajele reprezintă liantul întregii constructii si cheia comportamentului polimorfic al mediului Oberon/F. În esentă, mesajele sînt niste tipuri concrete extensibile care permit activarea indirectă a unei metode a unui obiect. De notat faptul că, în general, Oberon nu admite exportarea tipurilor concrete (pentru a evita binecunoscuta fragile base class problem), exceptii notabile fiind mesajele si tipurile mapper.

Mesajele sînt cel mai adesea folosite pentru notificarea unei actiuni a utilizatorului si pentru propagarea ei spre toate componentele interesate (broadcasting). Pentru a permite extensibilitatea, mesajele sînt definite de emitător. Receptorul tratează (printr-o procedură numită handler) doar mesajele care-l interesează, celelalte (inclusiv cele ce-i sînt necunoscute) fiind ignorate.

Există trei tipuri importante de mesaje: Controller messages, Model mes-sages si View messages. Pentru a "simti" fluxul mesajelor în Oberon/F să considerăm un exemplu: utilizatorul interactionează cu View-ul activ (numit focus). Presupunînd că interactiunea este tra-tată printr-un controller (deci nu este tratată direct de către view), lucrurile se vor petrece în felul următor:

Este de remarcat faptul că un acelasi model poate fi reprezentat vizual în mai multe moduri, de view-uri diferite. Mai multe astfel de reprezentări pot fi simultan vizibile. O modificare într-una din reprezentări conduce la actualizarea automată a celorlalte. Pe de altă parte, o aceeasi reprezentare (acelasi view) poate fi vizibilă simultan în mai multe ferestre (în frame-uri diferite). Modificarea se propagă prin acest mecanism în toate ferestrele.

Documente

Ca si modelele, view-urile sînt si ele extensii ale tipului Store, deci obiectele view sînt la rîndul lor persistente. Ele pot fi înglobate în alte obiecte persis-tene, cum ar fi alte view-uri sau modele, formînd o ierarhie oricît de complexă. Rădăcina unei astfel de ierarhii (nu nea-părat arborescentă; poate fi un graf orientat aciclic) se numeste document si reprezintă abstractiunea centrală în Oberon/F. Unui document îi corespunde unui fisier (extensia uzuală este .odc) si reprezintă obiectul-rădăcină afisat într-o fereastră. Altfel spus: orice apare într-o fereastră este un document.

Documentele din Oberon/F au toate caracteristicile imaginate în 1991 de Roger Levien (de la Xerox) pentru documentele viitorului:

Aplicatii posibile

Întregul mediu Oberon/F este de fapt o aplicatie, oferind o functionalitate intrinsecă. Posibilitătile de a utiliza texte complex formatate, cu legături spre alte documente, cu fragmente de text "pliate" (fold), cu elemente grafice (bitmap, WMF, Pict, etc), reprezintă exemple de astfel de functionalităti de ordin general.

Importante sînt însă posibilitătile de a extinde functionalitatea intrinsecă cu elemente specifice activitătii particulare a utilizatorului. Subsistemul de dezvoltare permite trei modalităti fundamentale de a ajunge la acest rezultat.

Cea mai simplă posibilitate de extindere a functionalitătii o reprezintă implementarea unor noi comenzi. O comandă este de fapt o procedură (exportată de un modul) care execută o operatie elementară. Pentru aceasta se utilizează interfetele publice ale modulelor disponibile (apartinînd mediului sau extensii ale acestuia), folosind limbajul Oberon/L într-o manieră asemănătoare limbajelor de scripting, apelînd eventual si la subsistemul de forme pentru a realiza o interfată mai complexă cu utilizatorul.

Comenzile legate de o anumită functionalitate se grupează în module, se compilează, se depanează si se testează, iar în final pot fi incluse în meniurile mediului sau chiar în documente. Un exemplu posibil de astfel de extensie ar putea fi un dialog care să caute elemente de text (Find/Replace) pe baza unor criterii de formatare (font, culoare, etc). Un exemplu practic este prezentant în caseta "Descarcă si compilează!".

O modalitate mai complexă de extindere a sistemului o reprezintă dezvoltarea unor componente noi care pot fi incluse în documente. Aceasta implică implementarea unui view (sau mai multe), cu toate tipurile, operatiile si comenzile necesare pentru afisarea, tipărirea, salvarea si restaurarea de pe disc, copiere sau mutarea prin clipboard, interactiunea cu utilizatorul, etc.

Posibile exemple de astfel de extensii ar putea fi implementarea unor instrumente simple de desenare (vectorială sau rastru), care ar putea fi incluse în documente si editate in place. Un alt exemplu l-ar putea reprezenta implementarea unor controale (echivalente comportamental si vizual VBX-urilor sau OCX-urilor). Desi această modalitate de extensie implică notiuni de programare avansată si o bună cunoastere a mediului, realizarea unor componente interactive este incomparabil mai simplă si mai naturală decît utilizînd tehnologia OLE 2. În plus, mediul Oberon/F generează automat schelete de module (cod sursă comentat) pentru principalele tipuri posibile de extensii. Un control simplu (dar perfect functional!) reprezintă mai putin de 150 de linii sursă. Încercati în C++ si faceti o comparatie.

În fine, cea mai complexă modalitate de extensie a mediului o reprezintă dezvoltarea unor întregi subsisteme destinate implementării unor containere care pot să includă ierarhii complexe de tipuri persistente. Un exemplu de astfel de subsistem este chiar subsistemul de forme din Oberon/F, pentru care este furnizat si întregul cod sursă.

Distribuirea aplicatiilor Oberon/F (fie că e vorba de seturi de comenzi, view-uri simple sau întregi subsisteme) se poate face fie împreună cu mediul Oberon/F, fie ca aplicatii stand-alone Windows sau Macintosh. Prima variantă nu implică nici un fel de taxe suplimentare de licentă (în conditiile în care nu se livrează si subsistemul de dezvoltare) nici din partea proiectantului si nici din cea a utilizatorului. A doua variantă implică utilizarea editorului de legături (linker) specific platformei. În acestă situatie, aplicatia nu poate fi extinsă în continuare de utilizator.

Aplicatii reale

Cu toate că este un produs foarte tînăr, există deja numeroase aplicatii reale în cele mai diverse domenii realizate cu ajutorul său iar rezultatele sînt spectaculoase. Un medic foloseste o aplicatie realizată în Oberon pentru achizitia si procesarea datelor furnizate de echipamentele de laborator iar o editură si-a dezvoltat o aplicatie specifică de machetare pentru un ziar. Societatea de asigurări Schweizer Ruck foloseste Oberon/F pentru instruirea inginerilor software. Siemens AG utilizează Oberon/F ca front-end pentru baze de date, iar NASA îl foloseste pentru a rezolva probleme de termodinamică si pentru a vizualiza rezultatele. Firma elvetiană Delta Engineering a dezvoltat o aplicatie profesională pentru proiectarea etichetelor cu coduri de bare, iar diverse universităti dezvoltă la rîndul lor aplicatii cu Oberon/F.

Un alt aspect important este legat de crearea unei piete de componente. Firma americană Applied Technology a lansat prima bursă on-line de componente software (http://www.wwww. com). Oberon microsystems actionează si pe post de clearing house, asigurînd unicitatea numelor de componente Oberon destinate comercializării (pentru a evita conflictele posibile cu numele altor module comerciale).

Viitorul

Următoarele versiuni vor aduce elemente care ar putea face din Oberon/F unul dintre cele mai puternice instrumente de dezvoltare de pe piată. Dintre acestea se disting subsistemele Sql (o interfată simplă, sigură si portabilă spre baze de date, bazată pe utilizarea driverelor ODBC pe 32 de biti) si Comm (suport TCP/IP pentru comunicatii în retele Ethernet). În luna aprilie 1996 este prevăzută lansarea compilatoarelor Direct-To-SOM si Direct-To-COM, urmînd ca mai tîrziu în acest an Oberon/F să fie complet integrat cu OLE si OpenDoc.

Informatii utile


(C) Copyright Computer Press Agora