dilungati, dilungati pure :-DIo prendo appunti ;-) :ugeek:
Citazione da: "cdimauro"@dsar: c'è qualche motivo per cui non apprezzi / ti piaccia FreePascal? Fra gli eredi del Pascal dopo quelli di casa Borland è fra i più gettonati e disponibile per parecchie piattaforme (persino per il GameBoy Advance, se non ricordo male).Il progetto FreePascal mi piace e penso sia un gran bel progetto, il problema è il linguaggio. Il Pascal è stato misconcepito, il suo obiettivo iniziale era un altro, non di certo creare un linguaggio per la programmazione reale. Il Pascal è stato anche molto criticato per dei problemi di design, Wirth ha partecipato al design di Algol-68 ed è autore di due linguaggi successivi a questo prima che il Pascal fosse stato concepito, possibile mai che abbia commesso errori così banali? :-)Inoltre Niklaus Wirth è un personaggio che impara molto dai suoi errori e questo è molto visibile nei suoi linguaggi successivi.
@dsar: c'è qualche motivo per cui non apprezzi / ti piaccia FreePascal? Fra gli eredi del Pascal dopo quelli di casa Borland è fra i più gettonati e disponibile per parecchie piattaforme (persino per il GameBoy Advance, se non ricordo male).
Un grosso deficit del Pascal è l'impossibilità di coesistere con i propri dialetti. Wirth è molto favorevole ai dialetti (lui in primis creava dialetti per uno scopo ben preciso!), ma il Pascal non era stato progettato per ciò. Per fare un linguaggio in cui molti dialetti possano coesistere ci vuole una distinzione tra reserved word ed identifier, che nei linguaggi di Wirth (eccetto il Pascal) viene fatta tramite l'uppercase dei reserved word.Per esempio se tu provassi a compilare il compilatore ISO-Pascal p4 o p5 con turbo pascal o freepascal, ti va in errore; perché operator è definito come identifier per enumerare gli operatori mentre in turbo pascal è un reserved word per creare operatori. Lo stesso al contrario, in ISO-Pascal "input" è un reserved word, mentre lo trovi spesso come identifier nei codici di turbo pascal.Se fossero state in uppercase, non sarebbero entrare in contrasto con gli identifier. In Modula-2 esistono tantissimi dialetti che introducono nuovi reserved word, ma questi dialetti possono ancora compilare il plain Modula-2. Per esempio c'erano dialetti che introducevano parallelismi o le classi tramite CLASS (sai quanto veniva usato parecchio class come identifier? in primis Wirth lo usava nei suoi compilatori).Un altro esempio è Modula-3, c'è stato un update del report che introduceva nuovi reserved word, questo non ha avuto alcuna influenza nel codice basato sul vecchio report. Ho odiato parecchio i reserved word in uppercase, ma credo che ora non saprei viverci, con un buon naming style per le variabili ti aiuta in leggibilità.
Un'altra cosa del Pascal che me lo fa puzzare di vecchio sono i puntatori e la non separazione tra il meaning del linguaggio e il compilatore. Reserved word come inline o packed non dovrebbero esistere, perché un linguaggio di alto livello in sé non dovrebbe avere direttive da dare al compilatore. Un record packed non ha un modo diverso di accesso agli elementi, una funzione inline non la chiami in modo diverso dalle normali procedure, inoltre non sempre si hanno vantaggi dall'uso di queste, dipende molto dalla piattaforma, quindi il tuo codice usando queste reserved word non è vero multiplatform.
Venendo ai puntatori, moltissime persone si chiedono perché Wirth abbia cambiato la dichiarazione dei puntatori da ^ptrList a POINTER TO List in Modula-2, molti credono per leggibilità, ma io sostengo che siano troppo pigri per leggere i paper scritti da Wirth ;-)
Verso la fine degli anni 70 si fece molto per alzare il livello dei linguaggi e renderli indipendenti dalla macchina, uno di questi fu togliere i puntatori. Il concetto di puntatore serviva solo per modellare le strutture dati, nient'altro. Questo concetto è molto presente in Oberon (un po' meno in Modula-2) in cui i puntatori possono solo puntare a record oppure array.
Infatti il simbolo di pointer dereferencing in Modula-2 era presente solo per facilitare le transizioni da Pascal a Modula-2 (come per esempio fu tenuto <> insieme a # per la diseguaglianza) ma aveva effetto nullo su questi tipi.Quindi fare List.item o List^.item è del tutto analogo. Un po' come l'inline, non cambia come accedi al field del tuo record. Da tenere in conto che in un linguaggio strong-typing il pointer dereferencing implicito è sempre safe.
Uno step più avanti è stato fatto in Modula-3 in cui il tipo OBJECT è automaticamente un reference type e non può essere deferenziato. Per la modellazione di dati si usa il recursive type di Hoare. TYPE List = OBJECT ... next : List END;
Non capisco come mai, in Oberon, Wirth non abbia abbandonato del tutto il pointer dereferencing, soprattutto lui che è un fan del data type ricorsivo di Hoare. Infatti in Oberon-07 lui ammette i puntatori solo ai record type. Credo sia per velocizzare il suo 1-pass compiler, il pointer dereferencing implicito richiede una query continua alla symbol table per capire il tipo di accesso e lui è ossessionato dai compilatori veloci :-) (il suo lexer usa direttamente interi, non enumerazioni o named integer).Wirth è un personaggio singolare, è sempre insoddisfatto.. vorrebbe eleganza e performance allo stesso tempo, ma ultimamente sta abbandonando troppo l'eleganza a favore delle performance del suo compilatore, credo che se continuasse a dedicarsi al language design arriverà a concepire un linguaggio peggiore del C. Quando si è anziani si cerca la semplicità ad ogni costo :-)
Riguardo il discorso puntatori quoto il libro di Tremblay, The Theory and Practice of Compiler Writing, nella sezione di Language Design a pagina 100 si trova:CitazioneThe second solution basically depends on what restrictions should be placed on the pointer. There are two restrictions which appear to fill the requirements. The first is to require the pointer to point to an object of a specific type. In other words, one does not declare a variable to be of type "POINTER"; one declares it to be of type, say, "POINTER TO integer." This restriction alone eliminates most of the hazards of pointers.The second restriction, which has been suggested by Wirth (1974), is that there should be no "address of" operator; that is, it should be possible to make a pointer to point at a named variable. Pointers should point only into anonymous, dynamically allocated heap storage. This largerly prevents the possibly serious confusion arising from referencing the same storage location under several different names.
The second solution basically depends on what restrictions should be placed on the pointer. There are two restrictions which appear to fill the requirements. The first is to require the pointer to point to an object of a specific type. In other words, one does not declare a variable to be of type "POINTER"; one declares it to be of type, say, "POINTER TO integer." This restriction alone eliminates most of the hazards of pointers.The second restriction, which has been suggested by Wirth (1974), is that there should be no "address of" operator; that is, it should be possible to make a pointer to point at a named variable. Pointers should point only into anonymous, dynamically allocated heap storage. This largerly prevents the possibly serious confusion arising from referencing the same storage location under several different names.
Poi ci sono altre piccole deficienze del Pascal risolte in Modula-2 ed Oberon ma mi sono dilungato troppo :-) cominciamo da queste
Se Modula-2 avesse usato dei reserved word in lowercase, non avrei potuto usare from e to; in alternativa avrei dovuto usare src e dst o source e target, che però a me non piacciono. L'espressività di copy from to è nettamente superiore di copy source target.
Il recursive data type? Credo tu lo conosca già, sono tipi che possono avere field dello stesso tipo che stai dichiarando. Nei vari linguaggi vengono usati i puntatori, Hoare invece ha astratto il concetto con il recursive data type (nel codice generato il compilatore usa i puntatori). In questo modo l'uso dei puntatori è totalmente superfluo.
type nodo: nodo successivo; int valore;end.
Secondo me uno step successivo è quello di rimuovere i NULL reference, inventati da Hoare e di cui si è pentito amaramente :-) ancora oggi nel 2011 si commettono errori dovuti al dereferencing di puntatori nulli. Esempio: http://www.kernel.org/pub/linux/kernel/ ... eLog-3.0.1 (il secondo).
Sarebbe interessante per esempio uno studio sulla sicurezza di un browser web scritto in uno di questi linguaggi :-)
Scusate la non tempestività ma è un periodo pieno di distrazioni
Citazione da: "cdimauro"Però a me non piace. Preferirei che fosse responsabilità del programmatore non far uso di parole inglesi, se non eventualmente composte (come si fa abitualmente). Ammetto, comunque, che l'arbitrarietà di questa scelta è incline a procurare problemi.Il problema è che il linguaggio poi non diventa dialetticamente estendibile, perché breaki il codice vecchio. Andrebbe bene in un linguaggio ben definito che non verrà mai esteso o di cui non esisterà alcun dialetto, ma questo non avviene mai. In C le estensioni infatti usano i doppi underscore __ per evitare che qualcuno abbia già usato nomi come identifier, che trovo orrendo!
Però a me non piace. Preferirei che fosse responsabilità del programmatore non far uso di parole inglesi, se non eventualmente composte (come si fa abitualmente). Ammetto, comunque, che l'arbitrarietà di questa scelta è incline a procurare problemi.
Per i nomi delle variabili a me piace una certa espressività dovuto ai termini in inglese, per esempio adoro i named parameters (non presenti in Modula-2 ma in Ada sì). Nella copia non so mai chi è il destinatario e il sorgente (ognuno adotta le sue convenzioni), quindi sarebbe comodo fare tipo:Strings.Copy(from = str1, to = str2);Se Modula-2 avesse usato dei reserved word in lowercase, non avrei potuto usare from e to; in alternativa avrei dovuto usare src e dst o source e target, che però a me non piacciono. L'espressività di copy from to è nettamente superiore di copy source target.Un caso grave è quello di Go, in cui "iota" viene usato come constant generator per le enumerazioni. In fisica noi usiamo le lettere greche per una miriade di coefficienti e costanti fisiche, non possono proibirmi l'uso di iota come identifier!
Citazione da: "cdimauro"Riguardo al packed, francamente sono un po' perplesso. Per la programmazione di basso livello ho sempre sentito l'esigenza di specificare dettagliatamente le risorse dell'hardware sottostante, come ad esempio di quanti byte è composto un intero, se è little o big endian, l'allineamento, se è read-only/write-only/read-write, e così via. Cose che nemmeno il C permette di fare.Però non vorrei che fossero introdotte keyword nel linguaggio per cose come queste. Preferirei le annotazioni, che sono diventate di moda negli ultimi anni.Be' sì ma io sottolineavo appunto il fatto che non ci dovrebbero essere reserved word che indichino qualcosa che abbia a che fare con il codice generato, per quello ci sono i pragma, per esempio i compilatori Modula-2 usano (*$ PACK *) o qualcosa di simile (non ricordo).Wirth invece odia i pragma ed anche se non lo ha specificato nel report nel system programming aveva tipi già con proprietà, per esempio SYSTEM.PACKEDSET o SYSTEM.PACKEDSTRUCT, eccetera eccetera.A me i pragma non piacciono nemmeno, l'idea di Wirth mi sembra più pulita (anche se limitata).
Riguardo al packed, francamente sono un po' perplesso. Per la programmazione di basso livello ho sempre sentito l'esigenza di specificare dettagliatamente le risorse dell'hardware sottostante, come ad esempio di quanti byte è composto un intero, se è little o big endian, l'allineamento, se è read-only/write-only/read-write, e così via. Cose che nemmeno il C permette di fare.Però non vorrei che fossero introdotte keyword nel linguaggio per cose come queste. Preferirei le annotazioni, che sono diventate di moda negli ultimi anni.
Citazione da: "cdimauro"Non è troppo limitativo? Puntare a un qualunque tipo, come un intero, perché non sarebbe utile (o, forse, "unsafe"?)Fare un puntatore ad intero non ha senso, crei possibili aliasing che poi il compilatore deve eliminare il più possibile con l'alias analysis. In C ne hai bisogno perché non c'è un vero passaggio per riferimento, poi non credo ci siano altri casi utili.. se non quello di rappresentare una stringa in un valore intero
Non è troppo limitativo? Puntare a un qualunque tipo, come un intero, perché non sarebbe utile (o, forse, "unsafe"?)
L'uso del puntatore per modellare strutture dati e basta penso sia sufficiente, c'è anche un browser web su Oberon System e nel non-system programming non usano SYSTEM.ADDRESS (che sarebbe il vero puntatore).Comunque sarebbe interessante qualche studio pratico di (grandi) software come un browser web scritto in qualche linguaggio strong typing tipo Modula-3 o Ada. Secondo me i bug di sicurezza sarebbero davvero ridotti alla logica, più sotto farò un esempio.
Citazione da: "cdimauro"Non lo conosco. Potresti darmi qualche dettaglio su come funziona?Il recursive data type? Credo tu lo conosca già, sono tipi che possono avere field dello stesso tipo che stai dichiarando. Nei vari linguaggi vengono usati i puntatori, Hoare invece ha astratto il concetto con il recursive data type (nel codice generato il compilatore usa i puntatori). In questo modo l'uso dei puntatori è totalmente superfluo.Comunque prima ho incollato una parte del Tremblay, che in realtà era solo "una seconda soluzione" da parte di Wirth :-) incollo quella di Hoare:CitazioneThe first solution is Hoare's recursive data types (Hoare, Dahl, and Dijkstra, 1972), which eliminate the explicit use of a pointer altogether. The basic idea behind recursive data types is that instead of having, say, one field of a record point to another record, the second record is conceptually a field of the first. A recursive data type is one in which the name of the type being defined occurs in its own definition. Such a notion has been used in the definition of a list in LISP and in defining a recursive pattern in SNOBOL 4, in particular. Trees can also be defined in such a manner. In actual fact the implementation at the machine level is the same, via a pointer, but recursive data types hide this completely from the programmer. A recursive data type is a relatively new concept, and it is too early yet to tell whether it will prove to be decisively superior to the alternative, namely, retaining the pointer but placing restrictions on it.Il tipo OBJECT è un type ricorsivo in Modula-3.
Non lo conosco. Potresti darmi qualche dettaglio su come funziona?
The first solution is Hoare's recursive data types (Hoare, Dahl, and Dijkstra, 1972), which eliminate the explicit use of a pointer altogether. The basic idea behind recursive data types is that instead of having, say, one field of a record point to another record, the second record is conceptually a field of the first. A recursive data type is one in which the name of the type being defined occurs in its own definition. Such a notion has been used in the definition of a list in LISP and in defining a recursive pattern in SNOBOL 4, in particular. Trees can also be defined in such a manner. In actual fact the implementation at the machine level is the same, via a pointer, but recursive data types hide this completely from the programmer. A recursive data type is a relatively new concept, and it is too early yet to tell whether it will prove to be decisively superior to the alternative, namely, retaining the pointer but placing restrictions on it.
Prima ho detto che sarebbe interessante uno studio sulla sicurezza dei programmi scritti in Ada o Modula-3. Ad esempio in Ada io posso specificare tipi non nulli con "is not null access" (in Ada i tipi puntatori si chiamano access type). In Modula-3 se provo a deferenziare un tipo reference senza controllare che sia nullo il compilatore mi da un warning fastidioso.Sarebbe interessante per esempio uno studio sulla sicurezza di un browser web scritto in uno di questi linguaggi :-)
Citazione da: "cdimauro"GLOM. Meglio che si fermi, se non altro per il buon nome che s'è fatto finora.Credo che Modula-2 sia l'ultimo linguaggio degno di nota, un linguaggio nel mezzo tra Modula-2 ed Oberon, sarebbe meglio. Preferirei un subset di Modula-3 (che comunque non ha fatto lui, ma lo ha seguito in modo indiretto). Modula-3 ha tutto ciò che serve unendo semplicità e completezza.In Oberon ci sono alcune porcherie per me inaccettabili, per esempio ha tolto il NOT ed AND a favore di ~ e & lasciando OR.Questo per rendere (secondo lui) le espressioni booleani leggibili ed evitare le ambiguità anche senza parentesi. In pratica il simbolo più piccolo ha la precedenza su quello visivamente più grande, quindi:(p & (~q)) OR (r & s) è facilmente leggibile e non ambiguo togliendo le parentesi con p & ~q OR r & s.
GLOM. Meglio che si fermi, se non altro per il buon nome che s'è fatto finora.
CitazioneIo non rimuoverei mai le parentesi, la leggibilità delle parentesi è nettamente superiore, a modo suo comunque ha voluto risolvere questo problema così. In Ada per evitare l'ambiguità sei costretto ad usare le parentesi sennò dà un errore in compile time.Preferisco evitare le parentesi, nella misura in cui un linguaggio abbia adottato un sistema di priorità che ricalchi quello in uso in matematica e che conoscono tutti.Nello specifico, gli operatori booleani and e or dovrebbero avere il primo priorità superiore al secondo, perché li considero moltiplicativo e additivo rispettivamente.Purtroppo non è sempre così.CitazioneCitazione da: "cdimauro"Concordo, ma parlando di programmazione di sistema, come tra l'altro riporta anche il titolo, come fai a implementare un gestore della memoria, ad esempio?Io sono per l'abolizione dei puntatori nella parte "safe" della programmazione, un browser web o un gestionale non ne avrebbe bisogno. Un protocollo di rete per esempio sì e per quello c'è la parte unsafe (che comunque è sempre una parte delimitata dei vari moduli).Insomma se c'è un segfault sai dove andare a cercare
Io non rimuoverei mai le parentesi, la leggibilità delle parentesi è nettamente superiore, a modo suo comunque ha voluto risolvere questo problema così. In Ada per evitare l'ambiguità sei costretto ad usare le parentesi sennò dà un errore in compile time.
Citazione da: "cdimauro"Concordo, ma parlando di programmazione di sistema, come tra l'altro riporta anche il titolo, come fai a implementare un gestore della memoria, ad esempio?Io sono per l'abolizione dei puntatori nella parte "safe" della programmazione, un browser web o un gestionale non ne avrebbe bisogno. Un protocollo di rete per esempio sì e per quello c'è la parte unsafe (che comunque è sempre una parte delimitata dei vari moduli).Insomma se c'è un segfault sai dove andare a cercare
Concordo, ma parlando di programmazione di sistema, come tra l'altro riporta anche il titolo, come fai a implementare un gestore della memoria, ad esempio?
Citazione da: "cdimauro"L'esempio che hai fatto è molto chiaro, ma basterebbe scrivere From e To, come suggeriva Z80Fan (io sono un amante del camel case ).Va contro il naming style di Modula-2/Oberon/Modula-3
L'esempio che hai fatto è molto chiaro, ma basterebbe scrivere From e To, come suggeriva Z80Fan (io sono un amante del camel case ).
Citazione da: "cdimauro"L'alternativa sarebbe quella di usare qualche simbolo per separare nettamente identificatori da keyword. Ad esempio @. Ma è molto più brutto che usare keyword tutte uppercase o lowercase (io preferirei quest'ultima, perché con le maiuscole mi sento gridare).Oppure $. Comunque alla fine basta ridimensionare il font dei reserved word nell'editor e non ci si fa più caso
L'alternativa sarebbe quella di usare qualche simbolo per separare nettamente identificatori da keyword. Ad esempio @. Ma è molto più brutto che usare keyword tutte uppercase o lowercase (io preferirei quest'ultima, perché con le maiuscole mi sento gridare).
Citazione da: "cdimauro"Dimenticavo: io sono per gli identificatori case insensitive. Per me (essere umano) il case sensitive in questi casi non ha proprio senso. Purtroppo è uno dei motivi di cruccio quando lavoro in Python.Ada è case insensitive, però lì il naming convention suggerito è molto verbose, nel senso che puoi trovare Number_of_tree o addirittura variabili molto lunghe, inizialmente lo apprezzavo ma ora preferisco altri naming style.
Dimenticavo: io sono per gli identificatori case insensitive. Per me (essere umano) il case sensitive in questi casi non ha proprio senso. Purtroppo è uno dei motivi di cruccio quando lavoro in Python.
Citazione da: "cdimauro"Un browser lo si può fare anche in Python, in cui non esistono i puntatori (è totalmente managed & safe; a parte un modulo, ctypes, che è stato introdotto di recente per importare librerie dinamiche).Sarebbe interessante un confronto, anche se credo che non venga utilizzato per il pregiudizio che sia stato fatto in un linguaggio diverso dal C, di conseguenza possono pensare a qualcosa di lento ed inefficiente.
Un browser lo si può fare anche in Python, in cui non esistono i puntatori (è totalmente managed & safe; a parte un modulo, ctypes, che è stato introdotto di recente per importare librerie dinamiche).
Citazione da: "cdimauro"Io sono un amante del NullObject (o Null Pattern). Per lo meno sarebbero eliminati i segmentation fault.Non elimini però i comportamenti inaspettati, il problema non è solo il segfault ma proprio che i programmatori dimenticano il check del null prima di ogni accesso, che sia un null reference o un null object.
Io sono un amante del NullObject (o Null Pattern). Per lo meno sarebbero eliminati i segmentation fault.
Per questo Hoare si è pentito di questa feature. Spec# (un superset rigoroso di C#) supportava i non-null type ma credo che il linguaggio non sia più sviluppato da microsoft.Hoare tenne una conferenza sul suo "billion dollar mistake", con il seguente abstract:CitazioneI call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years. In recent years, a number of program analysers like PREfix and PREfast in Microsoft have been used to check references, and give warnings if there is a risk they may be non-null. More recent programming languages like Spec# have introduced declarations for non-null references. This is the solution, which I rejected in 1965.I non null reference sono pure presenti in Ada 2005, è un obiettivo a cui i linguaggi futuri devono mirare, just to make the world better :-)
I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years. In recent years, a number of program analysers like PREfix and PREfast in Microsoft have been used to check references, and give warnings if there is a risk they may be non-null. More recent programming languages like Spec# have introduced declarations for non-null references. This is the solution, which I rejected in 1965.
def NullEvent(x, y): passclass Test: def __init__(self, CallBack = NullEvent) self.CallBack = CallBack def Process(self, x, y): self.CallBack(x, y)
class Test: def __init__(self, CallBack = None) self.CallBack = CallBack def Process(self, x, y): if (self.CallBack): self.CallBack(x, y)