从编程语言到编程语言集:一种新的语言分层思考
从编程语言到编程语言集
在接触过大量编程语言,甚至编写过自己的语言之后,目前我将编程语言分为四个等级,我认为这是最有用的分类方式:
- 4: 解释型,动态类型:JavaScript, Python, PHP
- 3: 解释型,静态类型:Hack, Flow, TypeScript, mypy
- 2: 编译型,自动内存管理 (静态类型):Go, Java (Kotlin), C#, Haskell, Objective-C, Swift
- 1: 编译型,手动内存管理 (静态类型):Rust, C, C++
还有第0级,汇编语言,但对于当今大多数程序员来说,这不是一个实用的选择。
现在,每种语言都在“易用性”和“性能”之间进行权衡。在这个层次结构中,编号越高,“级别越高”的语言越容易使用,而编号越低,“级别越低”的语言性能越高。
我假设对于大多数编程,尤其是“业务逻辑”类型的编程,我们希望使用一种位于该层次结构中间的语言。看看上面列出的语言,这并不奇怪。但有没有一种语言可以结合第二级和第三级呢?一种在开发过程中可以解释执行以实现快速迭代周期,但在部署时可以编译以获得更好性能的语言。尽管如此,目前还没有流行这样的语言。
现在让我们讨论第4级。一些重要的语言位于此级别,也许按程序员人数统计,它们是最流行的语言。缺乏静态类型的问题在于,很难在团队中大规模地处理此类代码。每个成功的企业最初都使用这些语言,但最终都会重写其代码库,以使用“较低级别”的语言,因为由许多人编写的大型代码库很难在没有静态类型检查器支持的情况下进行维护和修改。对于个人、小型项目,尤其是在代码可以轻松进行自动化测试的情况下,它们仍然是非常棒的语言。
现在对于第1级,Rust 在将第1级语言推广给更广泛的程序员方面做得非常出色。通过既现代又安全的设计,它允许更多的人编写需要最佳性能和资源利用率的代码。在这种情况下,Rust 应该是一个明确的选择。但是用 Rust 编写代码并不容易,不像用 JavaScript 或 Python 编写代码那样容易。同样的解决方案,虽然性能更高,但可能需要更多的代码行。
因此,我们来到了第2级和第3级,这是当今大多数专业程序员花费时间的地方。它们之间的权衡很明显:解释型语言具有更快的开发周期,因为程序员不需要等待编译步骤。但这会以性能为代价,因为解释器通常无法像编译器那样擅长优化和执行代码。
有趣的是,这些语言在表达能力上几乎相同。它们之间唯一的差距是,解释型语言可以包含 "eval" 和动态元编程(在运行时修改程序结构)。然而,在生产代码中通常会避免使用这些功能,它们在开发过程中更有帮助,尤其是在测试方面。
这里的讨论意味着公司需要在其代码库中使用至少 3 种,通常是 4 种不同的语言。这意味着需要维护 4 种不同的工具集。需要提供培训。需要招聘专家。而且通常是不相交的程序员群体,他们无法轻松地从一种语言跳转到另一种语言。
显然,永远不会有一种所有程序员都使用的单一语言。我们需要利用这个层次结构中列出的权衡。但我们可以做的是构建一个语言集,这将平滑这些级别之间的过渡。
作为这个语言集的基础,我建议使用 Rust。它是一个坚实的底层基础,可以用来构建我们的语言集。它具有现代的、经过深思熟虑的语言工具(包括像它的语法这样的东西)。
除了 Rust 之外,这个集合中将有 3 种语言:我们想要一个 2/3 级的混合语言和一个 4 级的语言。
让我们看一个例子来使这个概念具体化。首先是一个用 Rust 编写的程序:
fn main() {
let rect1 = Rectangle {width: 30, height: 50};
println!(“The area is {}.”, area(&rect1));
}
struct Rectangle {
width: u32,
height: u32,
}
fn area(rectangle: &Rectangle) -> u32 {
rectangle.width * rectangle.height
}
现在是用 RustGC 编写的程序,我们的 2/3 级混合语言:
fn main() {
let rect1 = Rectangle { width: 30, height: 50 };
println!(“The area is {}.”, area(rect1));
}
struct Rectangle {
width: int,
height: int,
}
fn area(rectangle: Rectangle) {
rectangle.width * rectangle.height
}
现在是用 RustScript 编写的程序,我们的 4 级语言:
fn main() {
let rect1 = { width: 30, height: 50 };
println!(“The area is {}.”, area(rect1));
}
fn area(rectangle) {
rectangle.width * rectangle.height
}
RustScript 可以用于大量的原型设计,特别是对于复杂的状态编程(交互式 UI)。 RustGC 是我们的主力,具有强大的异步支持,借助现代垃圾收集器获得了不错的性能,但没有与借用检查器作斗争的精神负担。 最后,当我们需要最大的性能和零成本抽象时,我们会选择 Rust。
RustGC 带有一个 VM,它允许即时保存 -> 执行的开发周期,但编译后会生成类似于 Rust 编译成的二进制文件,但附带一个 GC 运行时。
最好的部分是,所有三种语言都共享几乎相同的语法,并且它们的构建方式使得从更高级别的变体调用到更低级别的变体毫不费力。 这使我们能够从 2/3 级甚至 4 级语言中使用丰富的 Rust 生态系统。
更多例子。用 RustScript 编写的 UI component:
fn app() {
let (state, setState) = useState({
total: None,
next: None,
operation: None,
});
let handleClick = |buttonName| => {
setState(|state| => calculate(state, buttonName));
};
let value = state.next.or(state.total).unwrap_or("0");
<div className="component-app">
<Display value={value} />
<ButtonPanel clickHandler={handleClick} />
</div>
}
RustGC 中的异步示例:
async fn main() {
let user_ids = vec![1, 2, 3];
let user_names = user_ids.iter().map_async(
async |id| => fetch_user_name(id).await,
).await;
println!(user_names.join(", "));
}
async fn fetch_user_name(_: int) -> Future<string> {
// This could be a database request.
""
}