17611538698
webmaster@21cto.com

Wasm 联合创始人介绍新编程语言 Virgil

编程语言 0 388 2024-06-17 06:46:22

21CTO导读:Virgil 体现了面向“轻量级高性能系统”的语言趋势,该语言具有强大的交叉编译器。我们对其进行了测试。

图片

我最近看到Virgil语言的作者 Ben Titzer “发表”了一句话,他也是 WebAssembly 的共同创建者,他这样说道:

“我并不想与 Zig 竞争,但最近我把玩了一下C 语言的竞争对手 Zig,我很想知道哪种语言不会与它竞争”。

Titzer 还说 Rust“无法做到 Virgil 能做到的事情”。

Virgil 的目标是什么?

Titzer 在谈及新语言的目标说:

“我希望让 Virgil 成为一种出色的系统编程语言,它能去除遗留的垃圾,同时还具有编写健壮系统代码的强大功能。例如虚拟机、编译器、内核、网络堆栈等。”

除了 Rust,还有一种趋势是新语言瞄准“轻量级高性能系统”,并配备强大的交叉编译器。。

构建高性能系统背后的设计推理之一是编译器优化、代码树、展开分支、保护条件、安全性等复杂的组合。其中许多会随着时间的推移而变化,例如,今天内存很便宜,但安全性同样重要,但 30 年前情况恰恰相反。

在这篇文章中,我将重点介绍如何使用Virgil语言。我们将看看它与Zig和轻量级趋势相比如何。Virgil 有类和函数,甚至有类型参数,所以它给人的感觉也是很现代。

开始使用 Virgil


脱离上下文来看,要求选项有点不寻常:

图片

所以这一次,我的旧款 Macbook 又受到了本人的欢迎。

启动基于 Rust 的终端 Warp后,您只需克隆存储库即可拿到virgil。

如果您有一段时间没用过 GitHub,那么在存储库首页的代码选项卡下会为你显示克隆行:

图片

因此,现在我们只需在 Shell 中做如下克隆命令:

图片

现在,我可以从任何地方调用 Virgil。考虑到它的 bin 目录位置,我将添加到了系统路径:

export PATH=$PATH:~/Projects/TheNewStack/virgil/virgil/bin


这样,便搞定了!让我们再编写无法避免的第一个 Virgil 程序:

def main() {System.puts("Hello World!\n");}

我们使用内置解释器运行它,如下图所示:

图片

是不是很好?

但是,如果我们想编译它,我们需要针对主机和硬件架构。幸运的是,如果我们想不同主机上运行,Virgil 会做简单地检测:

图片

请大家注意,现在目录中有一个可执行文件。(虽然 Warp 向我们显示了时间,但请观察到我的机器是一台 2015 年 Macbook Pro ,它的年龄和状态,以免影响你的执行速度)

运行编译后的代码得到:

图片

虽然后续运行速度要快得多,但我们显然没有做足够的工作来考虑时间等问题。

上面我在本机平台上运行,否则,Virgil 会给我们一个 JAR。为了测试交叉编译器,让我们强制它快速生成一个 JAR:

图片

还有以下…

图片

因此,我们可以将其与 Zig 中的交叉编译功能进行比较。

让我们做到更多,比如得到可变类型var:

// 'var' introduces a new, mutable variable
var x: int = 0; // with type and initializervar y: int; // with type, initialized to defaultvar z = 0; // with initializer and inferred type


不可变变量的引入def方式完全相同。这是一个接受整数并返回整数的方法:

// recursive computation of fibonacci sequencedef fib(i: int) -> int {if (i <= 1) return 1; // base casereturn fib(i - 1) + fib(i - 2); // recursive calls}

def main() {System.puti(fib(6));}



上面的代码打印出了整数 13,这是应该的结果。我们可以将其放入一个类中,并将其保存为fib.v3:

class Fib {  def min: int = 1;  def calc(i: int) -> int {   if (i <= min) return min; // base case   return calc(i - 1) + calc(i - 2); // recursive calls  }}

def main() {var obj = Fib.new();var z = obj.calc(6); // method callSystem.puti(z);System.puts("\n");}


图片

代数数据类型


Virgil 特有的代数数据类型。这些似乎是多态性、开关和枚举的有趣组合,用于创建复杂的结构,而无需使用对象。


举个例子,以下是一个Travel类:

type Travel {  case Walk {    def distance(hoursTravelled: int) -> int {      return hoursTravelled * 3;    }  }  case Cycle {    def distance(hoursTravelled: int) -> int {      return hoursTravelled * 16;    }  }  case Drive (speed: int) {    def distance(hoursTravelled: int) -> int {      return speed * hoursTravelled;    }  }

def distance(hoursTravelled: int) -> int; // top-level method declaration}

def main() { var walking = Travel.Walk; var busTrip = Travel.Drive(50); var cycling = Travel.Cycle;
var totalDistance = walking.distance(1) + busTrip.distance(2) + cycling.distance(1); System.puts("Today, We covered a distance of "); System.puti(totalDistance); System.puts(" miles in 4 hours.n");}

// Today, We covered a distance of 119 miles in 4 hours.


该类型是一种不可变结构,附带一个顶级方法。它们可以进行深度比较以确定是否相等;case 和参数必须匹配。在其他方面,这些case值也像枚举类型 (enums) 一样。

Virgil 也有指针


在主机目标代码上,Virgil 确实也为开发者提供了指针,但这些指针本质上也是不安全的。


这是故意这样设计的,因为语言必须在字节级别拥有完全控制权。毕竟,我们被提醒“不仅整个编译器,而且整个运行时系统和垃圾收集器都是用 Virgil 编写!”


指针被实现为无类型的原始字节地址。它们的工作方式与 C 语言类似。它们的大小与目标类型相同,您可以对它们进行加减运算、比较等。


以下的指令load和store用于以“危险”的方式访问内存:

var p: Pointer;var x: int = p.load(); // load an int (i32) from {p}p.store(33); // store an int into {p}

var y: string = p.load(); // unchecked, raw reference load, dangerous!


这显然意味着开发者与主机、操作之间的关系与其它高级语言并不一样。

各位肯定知道一句话,“如果你长时间凝视深渊,深渊也会凝视你”,但还会导致无法追踪的错误。图片

结语


虽然 Virgil 语言还很年轻,但它已经具有很好的实用性了。


我没有介绍所有的功能,因为这篇小文只是一个甜点。但目前显然它是一个很活跃的项目。


您可以以面向对象的方式编码,也可以用函数式的方式编码。这有时被可爱的人们称为多范式语言,但最终,这是另一个强大且轻量级的项目,可以保持低级开发的健康。


作者:万能的大雄

参考网址:

https://github.com/titzer/virgil

https://github.com/titzer/virgil/blob/master/doc/tutorial/ADTs.md

评论