Et une souris et une grenouille. Compilateur universel

Dans une série sur la programmation fiable [1], [2] Swift est resté injustement oublié. Pour être honnête, je ne l'ai tout simplement pas considéré comme multiplateforme, mais travaillant exclusivement pour macOS / iOS. Il est arrivé par hasard que Swift soit également pris en charge par un environnement de développement tel que RemObjects Elements .

Il s'est avéré qu'elle avait un compilateur universel. Peut compiler des programmes en C #, Go, Java, Oxygene Object Pascal, Swift pour: Android, Cocoa (MacOS, iOS, tvOS), JVM, Linux (x64, armv6, aarch64), .NET / .NET Core / Mono, Windows natif (x86 / x64), WebAssembly.

Et il le fait dans presque toutes les combinaisons de langue → système cible! Par exemple, vous pouvez écrire un programme en Java qui utilisera WPF pour la plate-forme .NET cible, et tout cela dans les exemples fournis avec le package.

Je présente donc une mini-note sur RemObjects Elements, et en même temps sur la fiabilité des deux langages pris en charge - Swift et Oxygene.

Figure de radionetplus


Et en plus des discussions sur le problème de l'interopérabilité des différents environnements d'exécution - natifs, JVM, .NET, GC, ARC, cela s'est avéré tout simplement incroyable, et dans les deux sens, car au cours des discussions, ils ont conclu que les E / S normales étaient impossibles.

En bref sur les éléments RemObjects


Il s'agit soit d'un environnement de développement indépendant avec un débogueur, y compris un débogueur distant, et la complétion de code pour Windows ou macOS, ou il s'intègre à Visual Studio, et Xcode est requis pour Cocoa. Pour Swift, c'est gratuit, pour le reste, il en coûte de 199 $ pour la version pour les projets personnels, jusqu'à 799 $ pour une licence commerciale pour toutes les langues. Pour travailler avec un SGBD client-serveur, il est nécessaire de payer un supplément substantiel.

L'eau est le nom de la version Windows, elle est assez ascétique, elle n'a pas d'éditeur de formulaire visuel, mais sympathise avec la rigueur, et l'installateur ne prend que 700 Mo, bien sûr, sans JRE, .NET, Android NDK, etc.

Pour la gronder, ou je ne louerai pas beaucoup, elle remplit ses fonctions, elle n'est jamais tombée (mais la mémoire coule).

Le bonus pour l'IDE est beaucoup:

  • ( Water , -)
  • -
  • C#, Swift, Java, Delphi, C, Obj-C Oxygene, C#, Swift, Java, Go
  • Go- . Go
  • -
  • Delphi/VCL


Bien sûr, il y a un petit hic pour ceux qui pensent que (c) vous pouvez simplement prendre et transférer n'importe quel programme sur une autre plate-forme.

L'interface utilisateur ici est que le programme ne peut utiliser que les capacités de sa plate-forme cible RTL _et_ pour toutes les langues et leurs combinaisons. Autrement dit, aux fins de .NET, vous pouvez utiliser WPF, mais pas rt.jar, mais pour Native, uniquement WinAPI ou GTK, respectivement. Mais la bibliothèque de base écrite en Oxygène est disponible partout, tout comme la couche de migration avec Delphi - par la façon dont elles sont disponibles sur le github .

Un projet peut inclure des sous-projets dans différentes langues prises en charge par RO. Et avec l'importation de bibliothèques externes, il existe également des options bien développées.

La gestion de la mémoire sera utilisée à partir d'une plate-forme cible telle que ARC pour Cocoa. Je ne suis pas entré dans les détails, car Native GC est utilisé par défaut, bien qu'il y ait un choix - il est vérifié, il y en a dans mon projet sur github .

Ajoutez une observation. Si le programme a été écrit sous gestion manuelle de la mémoire (malloc / free), il fonctionnera simplement sous ARC. Et si le programme était sous ARC, alors il fonctionnera sans changements sous le GC (sauf pour la destruction immédiate).

Fiabilité


Oxygène


Il s'agit essentiellement d'un vieil Object Pascal familier, mais sous stéroïdes. La version Oxygene pour .NET a également été commercialisée sous le nom de Delphi Prism.

Il semble plus sûr en raison de:

  • Gc
  • prise en charge du contrôle nullable
  • disponibilité des contrats et des invariants
  • contrôle du registre d'identité
  • la capacité de contrôler l'indentation des paires de début / fin (on ne sait pas comment cela fonctionne)
  • méthodes de classe sécurisées pour les threads verrouillés / paresseux
  • en utilisant en utilisant, au sens de RAII

Moins. GC a également un inconvénient - non-déterminisme temporaire, consommation excessive de mémoire. Vous pouvez également noter les inconvénients que l'échelle de l'entreprise et de la communauté est petite et qu'il y a donc probablement plus d' erreurs de mise en œuvre que pour les technomonsters. La documentation est faible et le framework natif est minime, ce qui peut tirer un tas de «vélos» dans les projets si votre cible n'est pas .NET ou JRE.

Sur le plan technique, il a ajouté du sucre par rapport à Delphi:

  • async / wait / future, wait - pour l'instant uniquement pour .NET
  • LINQ
  • types génériques / dynamiques (différents de Delphi)
  • tuples
  • séquence / rendement
  • interpolation de chaîne

Interlude. C #


Il était auparavant éliminé en raison de la multiplicité des plates-formes, mais avec la sortie de .NET Core 3 et l'avènement du compilateur natif, y compris pour Linux, il est devenu un peu mieux. De plus, le langage est également pris en charge dans RemObjects avec une sélection arbitraire de cibles.

En fait, avec fiabilité, C # est plus ou moins correct. GC gâte la beauté, pas très à l'aise de travailler avec nullable, ce qui conduit à des NPE réguliers, à la possibilité d'obtenir une exception d'une fonction d'apparence innocente et à des problèmes avec une utilisation infructueuse de LINQ.

En raison du GC et de la consommation de ressources, il n'est pas très approprié pour Embedded. De plus, seul l'interpréteur sans JIT .NET Micro Framework a été abandonné pour être intégré depuis 2015, bien qu'il ait été développé sous le nom de TinyCLR

Maintenant sur Swift


En gros, un langage compilé par machine de type C, l'un des plus récents et créé en tenant compte de l'histoire de ses prédécesseurs. Fabriqué par Apple pour lui-même, le compilateur officiel est toujours sous Ubuntu, transféré en Open Source.

Les opportunités au niveau de la fiabilité ont accordé une attention décente. Je peux me plaindre de la possibilité de changer des classes constantes et de la possibilité de confondre une classe de référence avec une structure - une valeur, cependant ici comme en C #.

La gestion de la mémoire est dans l'ARC d'origine, et RemObjects pour les plates-formes autres qu'Apple a GC.
Lourd pour Embedded, pas de capacités en temps réel.

Le reste que j'aimerais voir est presque tout. Il n'y a pas de contrats (il y a des extensions non standard dans RemObjects), mais une sorte d'émulation est possible via Property Observers ou @propertyWrapper qui est apparu en 5.2 ( n'a pas encore été implémenté dans RemObjects ) Les

tuples doivent être notés, les noms des paramètres fonctions, array.insert(x, at: i)déballement explicite pour Facultatif et travail généralement pensé avec.

Une nuance essentielle, j'appellerais l'évolution du langage. De nombreux exemples du tutoriel officiel (5.2) ne fonctionnent tout simplement pas sur le même Repl.it (5.0), sans parler des RemObjects, qui ne savent pas exactement quelles versions correspondent exactement .

L'implémentation dans RemObjects diffère de celle de référence - Array est référencé ici, et String est immuable, les interfaces sont également différentes de celles décrites dans le didacticiel, et les interfaces de bibliothèque non seulement ont les leurs, mais varient légèrement entre les plates-formes. Ce qui apporte une certaine variété au processus de codage ennuyeux =) Le

tableau final de fiabilité du résumé mis à jour

En fait, je vous rappelle que ce n'est que superficiel selon les données de référence, et tous les pros qui écrivent dans ces langues sont invités à des corrections dures.

Qualité de compilation


Essayons de créer un programme Swift similaire à la distance Levenshtein dans l'article 0xd34df00d et le comparer avec les programmes à partir de là.

Rapide
/*    
	  Windows.Native, Elements.Island
*/

class Program {
	 public static func LevDist(_ s1: [UInt8], _ s2: [UInt8]) -> Int32! {
		 let m = s1.count
		 let n = s2.count
		 //  Edge cases.
		 if m == 0 {
			 return n
		 } else {
			 if n == 0 {
				 return m
			 }
		 }

		 var range = Range(0 ... (n + 1))
		 var v0: Swift.Array<Int64> = range.GetSequence()  //17ms

//         var v1 = v0;    // in Swift must copy, but RO make a ref
		 var v1 = Swift.Array<Int64>(v0);

		 var i = 0
		 while i < m {
			 v1[0] = i + 1
			 var j = 0
			 while j < n {
				 let substCost = (s1[i] == s2[j] ? v0[j] : v0[j] + 1)
				 let delCost = v0[j + 1] + 1
				 let insCost = v1[j] + 1
				 v1[j + 1] = substCost < delCost ? substCost : delCost
				 if insCost < v1[j + 1] {
					 v1[j + 1] = insCost
				 }
				 j += 1
			 }

			 let temp = v0; v0 = v1; v1 = temp // copy refs
			 i += 1
		 }
		 return v0[n]
	 }
 }


var b1 = [UInt8](repeating: 61 as! UInt8, count: 20000)
var b2: [UInt8] = b1
var b3 = Swift.Array<UInt8>(repeating: UInt8(63), count: 20000)

print("Start Distance");

var execTimer: StopWatch! = StopWatch()
execTimer.Start()

print(Program.LevDist(b1, b2))
print(Program.LevDist(b1, b3))

execTimer.Stop()

var execTime: Float64 = execTimer.ElapsedMilliseconds / 1000.0 / 10

print("\(execTime) s")
return 0


Le reste avec des changements minimes, bien que, bien sûr, les défauts les plus graves, je l'ai coupé sur github . Ceux qui n'ont pas peur et sont trop paresseux pour télécharger l'environnement et compiler, il y a aussi des binaires, si vous le souhaitez, vous pouvez exécuter des options JVM et NET relativement sûres, ou dans le bac à sable.

Les modifications concernent les modifications pour RO, la suppression de Encoding.UTF8.GetBytes de la partie mesure, et il s'est avéré que dans la version Pascal, la formation de lignes dans le formulaire for i := 1 to 20000 do s1 := s1 + 'a';peut prendre jusqu'à 4 minutes (en dehors de la partie mesure).

Tableau des résultats (normalisé par Java comme universel)
LanguePlate-formeCompilateurHeure sNormeParamètres
C #NET4.7NET4.7.306213 075445%-o +
C #NET Core 3.1Éléments 10.011 327385%version,> dotnet cs.dll
C #Win x64Éléments 10.06 312215%Libération
JavaJvmJDK 1.8.0.2422 941100%-g: aucun
$ java LevDist
JavaJvmÉléments 10.02,85197%release
$java -jar java8.jar
OxygeneNET4.7Elements 10.022,079751%release, range checking off
OxygeneWin x64Elements 10.09,421320%release, range checking off
SwiftJVMElements 10.023,733807%release
$java -jar swiftjvm.jar
SwiftWin x64Elements 10.0131,4004468%release
Go (Beta)Win x64Elements 10.089,2433034%release
Il serait intéressant de tester WASM, mais j'ai raté ce point.

Les mesures ont été effectuées dans une machine virtuelle avec Win7, ce qui ralentit cette tâche environ trois fois par rapport à mon matériel réel, la moyenne 3 a été tirée de 5 mesures.

Jusqu'à présent, il n'y a qu'une seule conclusion - la vie sur Swift est également possible en dehors de l'écosystème Apple. Mais jusqu'à présent pas rapide. L'hypothèse selon laquelle il existe un problème avec Win7, car le SDK Win10 est utilisé pour la compilation native, n'a pas été confirmée - sur le serveur 2016 1607, les heures sont à peu près les mêmes.

[1] Programmation fiable dans le contexte des langues - revue noob. Partie 1
[2] Programmation fiable dans le contexte des langages. Partie 2 - Challengers

All Articles