互联网计算机的专用工具,Motoko语言的介绍

前言
Motoko是一种现代编程语言,专门用于开发互联网计算机平台上的程序,也能作为在其他平台程序的通用语言。
易用性
Motoko是为那些使用过JavaScript或其他现代编程语言(如Rust、Swift、TypeScript、C#或Java),对面向对象或函数式编程习惯有一些基本了解的程序员所设计的。
异步消息通讯和类型安全
Motoko兼容主流的编程习惯,包括针对分布式应用程序的特殊编程抽象。每个应用程序由一个actor组成,该actor与其他actor通讯时,并不共享状态,而是使用(异步)消息通讯。
Motoko基于actor的编程抽象允许了人类可读的消息传递模式(human-readable message-passing),它强制规定每次网络交互都要遵守某些规则并避免常见错误。
特别地,由于Motoko包含了一个实用的现代类型系统,该系统可以在每个程序执行之前对其类型进行检查,因此Motoko程序具有良好类型安全性。
Motoko的类型系统会静态检查每个Motoko程序在所有可能的输入下能否安全地执行,并且不会发生内部类型错误。这就排除了其他语言中常见的类型陷阱,包括空指针错误、参数和结果类型不匹配等等问题。
Motoko程序会静态地编译为WebAssembly执行,WebAssembly是一种便于多平台移植的二进制格式,几乎能运行在所有现代计算机硬件上,因此可以在互联网与互联网计算机上被广泛地执行。
微服务即actor
Motoko为开发者提供了一个基于actor的编程模型来实现服务操作,包括互联网计算机上的微服务。
actor类似于对象,其特殊性在于它的独立状态是远程方式(remotely),并且它与外界的交互是异步的。
所有与actor的通信以及actors之间的通讯,都需要使用互联网计算机的消息传递协议,在网络中异步地传递消息。actor的消息是按顺序处理的,因此状态修改不会导致竞态条件。
互联网计算机提供的底层计算平台确保了每一个基于消息的同步都能关闭,但这样做时,分布式系统中常见的超时等原因也可能导致同步失败。
异步actors
和大部分现代编程语言一样,Motoko允许使用符合人体工程学的语法去实现组件之间的异步通信。
在Motoko中,每个通信组件都是一个actor。作接下来举一个例子,假如现在你本人就是一个actor程序,请看以下三行代码:
let result1 = service1.computeAnswer(params);
let result2 = service2.computeAnswer(params);
finalStep(await result1, await result2)
我们可以通过以下三个步骤来描述程序的行为:
1.该程序向两个不同的服务发出两个请求(第1、2行),这两个服务都是由actor内部实现的;
2.程序使用关键字await等待每一个结果都就绪(第3行)。
3.程序通过调用finalStep函数使用这两个结果(第3行)。
一般来说,服务会交错执行而不是互相等待,这样可以减少总体延迟。然而,如果我们试图在没有特殊语言的支持下以这种方式减少延迟,将破坏系统的清晰性和简洁性。
即使在没有交错执行的情况下(如果上面只有一个调用),出于同样的原因,编程抽象仍然清晰和简洁。Motoko会向编译器发出在哪里需要转换程序的信号,程序员不必为将程序的执行与底层系统的消息传递循环交叉,而去调整程序本身的逻辑。
在这里,程序在第3行中使用 await ,通过使用Motoko提供的人类可读语法,以一种简单的方式来表示交叉行为。
在缺乏这些抽象的语言设置中,开发人员不仅需要直接调用这两个函数,而且必须使用非常高级的编程模式,可能会在系统提供的“事件处理程序”中注册“回调函数”。每个回调都将处理在应答就绪时出现的异步事件。
这种系统级编程功能虽然强大,但非常容易出错,因为它会把高级数据流分解为通过共享状态进行通信的低级系统事件。有时这种方式是必要的,但在互联网计算机里就不是必须的。
相反,我们的程序避免了这种更底层却更繁琐的编程风格,即每个请求都类似于一个普通的函数调用。虽然就像当今大多数现代软件所做的,人们越来越多地把这种更简单、更程式化的编程风格用在表达与外部环境交互的实际系统中。但这样就需要特殊的编译器和类型系统支持,我们将在下面详细讨论。
支持异步行为
在异步计算设置中,允许程序及其运行环境执行并发的内部计算。
具体来说,异步程序是指那些程序在处理其环境的请求时,不需要等待环境的程序。同时,允许程序在等待时(可能是主动的)在此环境中进行内部处理。在上面的示例中,程序在等待第一个微服务的同时发出了第二个请求。
相对的,环境向程序发起请求,环境也不需要在等待返回响应的同时,等待该程序的响应围绕其进行外部处理。
我们上面没有列出这种“notify”模式的例子,因为它使用了回调(以及高阶函数和控制流),因此显得更加复杂
async与await的语法形式
为了满足清晰和简洁的需求,Motoko采用了常见的async和await的程序构造,从而为程序员提供了一种结构化语言来描述复杂的异步依赖关系。
这个异步语法会在将来引入异步数据的“promise”(在上面的第一个示例中未显示)。当我们在Actors和异步数据中引入actor时,您将了解到更多有关异步promise的信息。
在这里,我们仅使用调用service1.computeAnswer(params)、service2.computeAnswer(params)所产生的代码。
语法await将在预先的promise上进行同步。我们在上面的示例中展示了await表单的两种用法,它们等待着这两个服务的结果。
当开发人员使用这些关键字时,编译器会根据需要对程序进行转换,通常会对程序的实现和数据流进行复杂的转换,而这些转换将很繁琐。同时,Motoko的类型系统为这些构造写死了一些正确的使用模式,包括在消息的“消费者”和“生产者”之间流动的类型始终保持一致,并且允许服务之间发送的数据类型也将符合这些规则,并且不包含私有的可变状态。
稳定的类型
与其他现代编程语言一样,Motoko允许每个变量携带函数、对象或原始数据(例如字符串、整数)。也存在其他类型的值,包括records、tuples和称为variants的“标记数据”。
Motoko拥有类型安全的形式属性,也称为类型稳定性。类型友好型的Motoko程序不会出错,这意味着它们不会因为把程序结构当作错误的类型来对待,而错误的使用它们。
例如,Motoko程序中每个变量都带有一个关联类型,在程序执行之前,该类型是静态且明确的。编译器会检查每个变量的每次使用,以防止运行时出现类型错误,包括空指针错误。
从这个意义上讲,Motoko的类型在程序源代码中提供了一份经过编译器验证的可信任文档。
通常,动态测试可以实现Motoko类型系统无法达到的检查能力。Motoko虽然包含了较前卫的编程思想,但我们并不想让这个类型系统变得晦涩且难以理解。相反,Motoko的类型系统吸取了现代编程思想、易用性思想以及已有的类型系统的经验教训,从而为通用分布式编程提供了一种更易用、数学上更精确的语言。