Y un ratón y una rana. Compilador universal

En una serie sobre programación confiable [1], [2] Swift permaneció inmerecidamente olvidado. Para ser honesto, simplemente no lo consideraba multiplataforma, sino que trabajaba exclusivamente para macOS / iOS. Sucedió por casualidad que Swift también es compatible con un entorno de desarrollo como RemObjects Elements .

Resultó que ella tenía un Compilador Universal. Puede compilar programas en C #, Go, Java, Oxygene Object Pascal, Swift para: Android, Cocoa (MacOS, iOS, tvOS), JVM, Linux (x64, armv6, aarch64), .NET / .NET Core / Mono, Windows nativo (x86 / x64), WebAssembly.

¡Y lo hace en casi cualquier combinación de idioma → sistema de destino! Por ejemplo, puede escribir un programa en Java que usará WPF para la plataforma .NET de destino, y todo esto está en los ejemplos que vienen con el paquete.

Por lo tanto, presento una mini nota sobre RemObjects Elements y, al mismo tiempo, sobre la fiabilidad de los dos idiomas admitidos: Swift y Oxygene.

Figura de radionetplus


Y además de las discusiones sobre el problema de la interoperabilidad de los diferentes tiempos de ejecución: nativo, JVM, .NET, GC, ARC, resultó ser simplemente increíble, y en ambos sentidos, ya que durante las discusiones llegamos a la conclusión de que IO normal es imposible.

Brevemente sobre RemObjects Elements


Este es un entorno de desarrollo independiente con un depurador, incluido uno remoto, y finalización de código para Windows o macOS, o se integra con Visual Studio, y se requiere Xcode para Cocoa. Para Swift, es gratis, por lo demás cuesta desde $ 199 para la versión para proyectos personales, hasta $ 799 para una licencia comercial para todos los idiomas. Para trabajar con DBMS cliente - servidor es necesario pagar mucho más.

El agua es el nombre de la versión de Windows, es bastante ascético, no tiene un editor de formas visuales, pero simpatiza con la rigurosidad, y el instalador solo toma 700 MB, por supuesto, sin incluir JRE, .NET, Android NDK, etc.

Para regañarla, o no la alabaré mucho, ella realiza sus funciones, nunca ha caído (pero la memoria fluye).

La bonificación al IDE es mucho:

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


Por supuesto, hay una pequeña trampa para aquellos que piensan que (c) puede simplemente tomar y transferir cualquier programa a otra plataforma.

El OI aquí es que el programa solo puede usar las capacidades de su plataforma RTL _y_ objetivo para todos los idiomas y sus combinaciones. Es decir, para el propósito de .NET, puede usar WPF, pero no rt.jar, sino para Native, solo WinAPI o GTK, respectivamente. Pero la biblioteca base escrita en Oxygene está disponible en todas partes, al igual que la capa de migración con Delphi, por cierto, están disponibles en el github .

Un proyecto puede incluir subproyectos en diferentes idiomas compatibles con RO. Y con la importación de bibliotecas externas, también hay opciones bien desarrolladas.

La gestión de memoria se utilizará desde una plataforma de destino como ARC para Cocoa. No entré en detalles, porque Native GC se usa de forma predeterminada, aunque hay una opción: está marcada, está en mi proyecto github .

Agrega una observación. Si el programa fue escrito bajo administración de memoria manual (malloc / free), funcionará simplemente bajo ARC. Y si el programa estaba bajo ARC, entonces funcionará sin cambios bajo el GC (excepto por la destrucción inmediata).

Fiabilidad


oxígeno


Esto es básicamente un viejo Object Pascal familiar, pero con esteroides. La versión Oxygene para .NET también se comercializó como Delphi Prism.

Se ve más seguro debido a:

  • Gc
  • soporte de control anulable
  • disponibilidad de contratos e invariantes
  • control de registro de identidad
  • La capacidad de controlar la sangría de los pares de inicio / fin (no está claro cómo funciona)
  • métodos de clase segura de subprocesos bloqueados / perezosos
  • utilizando utilizando, en el sentido de RAII

Desventajas GC también tiene una desventaja: no determinismo temporal, consumo excesivo de memoria. También puede escribir las desventajas de que la escala de la empresa y la comunidad es pequeña y, por lo tanto, probablemente haya más errores de implementación que para los monstruos tecnológicos. La documentación es débil y el marco nativo es mínimo, lo que puede atraer un montón de "bicicletas" a proyectos si su objetivo no es .NET o JRE.

En el aspecto técnico, agregó azúcar en relación con Delphi:

  • asíncrono / espera / futuro, espera, hasta ahora solo para .NET
  • LINQ
  • tipos genéricos / dinámicos (diferentes de Delphi)
  • tuplas
  • secuencia / rendimiento
  • interpolación de cuerdas

Interludio. C #


Anteriormente se eliminó debido a la multiplataforma limitada, pero con el lanzamiento de .NET Core 3 y el advenimiento del compilador nativo, incluso para Linux, se volvió un poco mejor. Además, el lenguaje es igualmente compatible con RemObjects con una selección arbitraria de objetivos.

En realidad, con confiabilidad, C # está más o menos bien. GC estropea la belleza, no es muy cómodo trabajar con nulos, lo que conduce a NPE regulares, la capacidad de obtener una excepción de una función de aspecto inocente y problemas con el uso fallido de LINQ.

Debido al consumo de GC y recursos, no es muy adecuado para Embedded. Además, solo el intérprete sin JIT .NET Micro Framework ha sido abandonado para incrustar desde 2015, aunque se desarrolló como TinyCLR

Ahora sobre Swift


En general, un lenguaje compilado en máquina tipo C, uno de los más nuevos y creados teniendo en cuenta la historia de sus predecesores. Hecho por Apple para sí mismo, el compilador oficial todavía está bajo Ubuntu, transferido a Open Source.

Las oportunidades a nivel de confiabilidad prestaron una atención decente. Me puedo quejar de la posibilidad de cambiar las clases constantes y la posibilidad de confundir una clase de referencia con una estructura, un valor, sin embargo aquí como en C #.

La gestión de memoria está en el ARC original, y RemObjects para plataformas que no sean Apple tiene GC.
Pesado para Embedded, sin habilidades en tiempo real.

El resto que me gustaría ver es casi todo. No hay contratos (hay extensiones no estándar en RemObjects), pero es posible algún tipo de emulación a través de Property Observers o @propertyWrapper que apareció en 5.2 ( aún no se ha implementado en RemObjects ) Tuples

deben tenerse en cuenta, nombres de parámetros funciones, array.insert(x, at: i)desenvolvimiento explícito para Opcional, y generalmente pensado trabajar con él.

Un matiz esencial, llamaría la evolución del lenguaje. Muchos ejemplos del tutorial oficial (5.2) simplemente no funcionan en el mismo Repl.it (5.0), sin mencionar RemObjects, que no están claros qué versiones corresponden exactamente .

La implementación en RemObjects difiere de la referencia: aquí se hace referencia a Array, y String es inmutable, y las interfaces también difieren de las descritas en el tutorial, y las interfaces de la biblioteca no solo tienen las suyas, sino que varían ligeramente entre plataformas. Lo que aporta cierta variedad al proceso de codificación aburrido =) El

resumen final actualizó la tabla de confiabilidad

En realidad, le recuerdo que esto solo es superficial de acuerdo con los datos de referencia, y todos los profesionales que escriben en estos idiomas están invitados a realizar ediciones duras.

Calidad de compilación


Tratemos de hacer un programa Swift similar a la distancia de Levenshtein en el artículo. 0xd34df00d y compáralo con los programas de allí.

Rápido
/*    
	  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


El resto con cambios mínimos, aunque, por supuesto, los defectos más graves, recorté en github . Aquellos que no tienen miedo y son demasiado flojos para descargar el entorno y compilar, también hay binarios allí, si lo desea, puede ejecutar opciones JVM y NET relativamente seguras, o en el sandbox.

Los cambios se relacionan con las ediciones para RO, la eliminación de Encoding.UTF8.GetBytes de la parte de medición, y resultó que en la versión Pascal la formación de líneas en el formulario for i := 1 to 20000 do s1 := s1 + 'a';puede tomar hasta 4 minutos (fuera de la parte de medición).

Tabla de resultados (normalizada por Java como universal)
LenguaPlataformaCompiladorTiempo sNormaParámetros
C #NET4.7NET4.7.306213,075445%-o +
C #NET Core 3.1Elementos 10.011,327385%lanzamiento,> dotnet cs.dll
C #Gana x64Elementos 10.06.312215%lanzamiento
JavaJvmJDK 1.8.0.2422.941100%-g: ninguno
$ java LevDist
JavaJvmElementos 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
Sería interesante probar WASM, pero me perdí este punto.

Las mediciones se llevaron a cabo en una máquina virtual con Win7, lo que ralentiza esta tarea aproximadamente tres veces con respecto a mi hardware real, el promedio de 3 se tomó de 5 mediciones.

Hasta ahora solo hay una conclusión: la vida en Swift también es posible fuera del ecosistema de la manzana. Pero hasta ahora no rápido. La hipótesis de que hay un problema con Win7, debido a que el SDK de Win10 se utiliza para la compilación nativa, no se ha confirmado: en Server 2016 1607, los tiempos son casi iguales.

[1] Programación confiable en el contexto de idiomas - revisión novata. Parte 1
[2] Programación confiable en el contexto de los lenguajes. Parte 2 - Retadores

All Articles