还有一只老鼠和一只青蛙。通用编译器

在一系列有关可靠编程的文章中[1],[2] Swift仍然被人们遗忘了。老实说,我只是不认为它是跨平台的,而是专门为macOS / iOS而工作。偶然的是,Swift也得到了RemObjects Elements等开发环境的支持

原来她有一个通用编译器。可以在以下C#,Go,Java,Oxygene Object Pascal,Swift中编译程序:Android,可可(MacOS,iOS,tvOS),JVM,Linux(x64,armv6,aarch64)、. NET / .NET Core / Mono,本机Windows (x86 / x64),WebAssembly。

并且它几乎以任何语言→目标系统的组合来实现!例如,您可以用Java编写一个程序,该程序将WPF用于目标.NET平台,并且程序包随附的示例中都包含了这些。

因此,我提出了一个有关RemObjects Elements的迷你说明,同时介绍了其中支持的两种语言-Swift和Oxygene的可靠性。

来自radionetplus的


而且除了讨论不同的运行时环境(本机,JVM,.NET,GC,ARC)的互操作性问题之外,事实证明这简直令人难以置信,而且从两种意义上讲,因为在讨论中它们得出的结论是普通IO是不可能的。

简要介绍RemObjects元素


这是一个带有调试器的独立开发环境,其中包括一个远程调试器,并且适用于Windows或macOS的代码完成,或者它与Visual Studio集成,并且Cocoa需要Xcode。对于Swift来说,它是免费的,其余的价格从个人项目版本的199美元到所有语言的商业许可证的799美元不等。对于使用客户端-服务器DBMS的系统,必须支付大量额外费用。

Water是Windows版本的名称,它相当苦行,它没有可视的表单编辑器,但是严格要求同情,安装程序仅占用700MB,当然不包括JRE,.NET,Android NDK等。

要责骂她,或者我不会赞美她,她履行了自己的职责,但从未跌倒(但记忆不断)。

IDE的好处很多:

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


当然,对于那些认为(c)您可以将任何程序转移到另一个平台上的人来说,都是很少的收获。

这里的OI是程序只能针对所有语言及其组合使用其RTL目标平台的功能。也就是说,就.NET而言,您可以使用WPF,但不能使用rt.jar,但对于本机,只能分别使用WinAPI或GTK。但是用Oxygene编写的基础库随处可见,Delphi的迁移层也是如此(通过github上可用的方式)

一个项目可以包含RO支持的不同语言的子项目。随着外部库的导入,也有完善的选择。

将从目标平台(例如ARC for Cocoa)使用内存管理。我没有详细介绍,因为默认情况下会使用Native GC,尽管可以选择-已选中,但我的项目在github上

添加一个观察值。如果程序是在手动内存管理(malloc / free)下编写的,则它将仅在ARC下运行。而且,如果该程序在ARC下,则无需更改即可在GC下运行(除非立即销毁)。

可靠性


氧气


这基本上是一个古老的熟悉的对象Pascal,但是在类固醇上。.NET版本的Oxygene也以Delphi Prism的形式出售。

由于以下原因,它看起来更安全:

  • GC
  • 可为空的控件支持
  • 合同和不变式的可用性
  • 身份注册控制
  • 控制开始/结束对的缩进的能力(尚不清楚其工作方式)
  • 锁定/惰性线程安全类方法
  • 在RAII的意义上使用使用

缺点。GC也有一个缺点-暂时的不确定性,过多的内存消耗。您还可以写下公司和社区规模较小的缺点,因此,与技术怪兽相比,实现错误可能更多。文档薄弱,本机框架很少,如果目标不是.NET或JRE,则可以将大量“自行车”拖入项目中。

在技​​术方面,相对于Delphi,它添加了糖:

  • 异步/等待/将来,等待-到目前为止仅适用于.NET
  • LINQ
  • 通用/动态类型(与Delphi不同)
  • 元组
  • 顺序/产量
  • 字符串插值

插曲。C #


以前由于跨平台有限而被取消,但是随着.NET Core 3的发布以及本机编译器(包括Linux)的出现,它变得更好了。此外,RemObjects也支持任意选择的目标语言。

实际上,凭着可靠性,C#差不多可以了。GC破坏了美观性,使用nullable并不是很舒服,这导致常规的NPE,无辜的外观功能获得异常的能力以及LINQ使用不成功的问题。

由于GC和资源消耗,它不太适合嵌入式。此外,自2015年以来,只有没有JIT .NET Micro Framework的解释器才被放弃嵌入,尽管它是作为TinyCLR开发的

现在关于Swift


总的来说,这是一种类似于C的机器编译语言,是考虑到其前辈的历史而最新创建的。官方编译器由Apple自己制造,仍在Ubuntu之下,已转移到Open Source。

可靠性级别的机会受到了关注。我可能会抱怨更改常量类的可能性以及将引用类与结构(值)混淆的可能性,但是在这里像在C#中那样。

内存管理位于原始ARC中,并且Apple以外的其他平台的RemObjects具有GC。
嵌入式很重,没有实时功能。

我想看的剩下的几乎是所有东西了,没有合同(RemObjects中有非标准扩展名),但是可以通过5.2中出现的Property Observers或@propertyWrapper进行某种模拟(尚未在RemObjects中实现),

应注意元组,参数名称函数,array.insert(x, at: i)为Optional显式展开,并且通常考虑使用它。

一个基本的细微差别,我称之为语言的发展。官方教程(5.2)中的许多示例根本无法在同一个Repl.it(5.0)上运行,更不用说RemObjects了,不清楚不清楚哪个版本完全对应

RemObjects中的实现与参考中的实现不同-此处引用了Array,并且String是不可变的,并且接口也与本教程中描述的接口不同,并且库接口​​不仅具有自己的接口,而且在平台之间也略有不同。这给无聊的编码过程带来了一些变化=)

最终摘要更新了可靠性表

实际上,我提醒您,这只是根据参考数据而言的肤浅表述,所有以这些语言编写的专家都被邀请进行硬编辑。

编译质量


让我们尝试制作一个类似于Levenshtein距离的Swift程序 0xd34df00d 并将其与那里的程序进行比较。

迅速
/*    
	  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


剩下的改动很小,尽管当然是最严重的缺陷,我在github上进行了修整那些不害怕并且懒于下载环境和进行编译的人,那里也有二进制文件,如果您愿意,您可以运行相对安全的JVM和NET选项,也可以在沙箱中运行。

所做的更改与对RO的编辑,从度量部分中删除Encoding.UTF8.GetBytes有关。事实证明,在Pascal版本中,表格中的线条形成for i := 1 to 20000 do s1 := s1 + 'a';可能需要长达4分钟的时间(在度量部分之外)。

结果表(由Java标准化为通用表)
平台编译器时间s规范参量
C #NET4.7NET4.7.306213,075445%-o +
C #NET Core 3.1元素10.011,327385%发布,> dotnet cs.dll
C #赢x64元素10.06,312215%释放
爪哇虚拟机JDK 1.8.0.2422,941100%-g:无
$ java LevDist
爪哇虚拟机元素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
测试WASM会很有趣,但是我错过了这一点。

这些测量是在装有Win7的虚拟机上进行的,相对于我的真实硬件,该速度使这项任务的速度降低了大约三倍,平均是从5次测量中

得出的。但是到目前为止还不算快。Win7存在问题的假设(因为Win10 SDK用于本机编译)尚未得到证实-在Server 2016 1607上,时间大致相同。

[1] 在语言环境中进行可靠的编程-noob评论。第1部分
[2] 在语言环境中进行可靠的编程。第2部分-挑战者

All Articles