Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
ZhiruiLi committed Mar 31, 2023
1 parent 4cdfc47 commit d01b93b
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 2 deletions.
Binary file added images/2023-04-01-07-23-17.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 12 additions & 2 deletions posts/verse-lang/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<span class=logo__cursor></span></a>
<span class=header__right><nav class=menu><ul class="menu__inner menu__inner--desktop"><li><a href=/archive>Archive</a></li><li><a href=/tags>Tags</a></li><li><a href=https://www.github.com/zhiruili>Github</a></li><li><a href=/index.xml>RSS</a></li></ul><ul class="menu__inner menu__inner--mobile"><li><a href=/archive>Archive</a></li><li><a href=/tags>Tags</a></li><li><a href=https://www.github.com/zhiruili>Github</a></li><li><a href=/index.xml>RSS</a></li></ul></nav><span class=menu-trigger><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/></svg></span><span class=theme-toggle><svg class="theme-toggler" width="24" height="24" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M22 41c10.4934.0 19-8.5066 19-19C41 11.5066 32.4934 3 22 3 11.5066 3 3 11.5066 3 22s8.5066 19 19 19zM7 22C7 13.7157 13.7157 7 22 7V37C13.7157 37 7 30.2843 7 22z"/></svg></span></span></span></header><div class=content><div class=post><h1 class=post-title>Epic 新语言 Verse 介绍</h1><div class=post-meta><span class=post-date>2023-03-29</span></div><span class=post-tags><a href=/tags/unreal/>#Unreal</a>&nbsp;
<a href=/tags/verse/>#Verse</a>&nbsp;</span><div class=post-content><h2 id=verse-语言的由来>Verse 语言的由来
<a href=#verse-%e8%af%ad%e8%a8%80%e7%9a%84%e7%94%b1%e6%9d%a5 class=h-anchor aria-hidden=true>#</a></h2><p>Verse 是 Epic 开发的新编程语言,由 Haskell 圈的大佬 SPJ 主导开发。</p><p>我们知道,UE 本身使用 C++ 开发,也允许使用 C++ 来对引擎进行扩展,在引擎内部也提供了蓝图作为官方的可视化编程语言。另外,随着用户群体的扩大,市面上也出现了诸如 puerts、unlua 等第三方的脚本语言方案,可以说生态上已经比较完备了。那为什么此时 Epic 还要再发明一个新的语言呢?</p><p>关于这个问题,SPJ 在 Haskell eXchange 上做过一个<a href="https://www.youtube.com/watch?v=832JF1o7Ck8">分享</a>,提到了其中的原因。Epic 的老板 Tim Sweeney 经常在鼓吹元宇宙(Metaverse),在他看来,元宇宙有如下的特点:</p><ul><li>人们可以在一个共享实时 3D 模拟世界中进行社交互动</li><li>这个世界中有一个开放的经济体系,这个体系有规则但没有某些企业作为霸主</li><li>这个世界是一个对所有程序员、艺术家、设计师开放的创作平台,而不是一个封闭的花园</li><li>这个世界不是由一堆编译好的分离的应用集合而成,所有人的代码和内容都能互操作,都能实时动态地更新代码</li><li>标准是普遍开放的,不被 Unreal 独占,也能使用其他的引擎如 Unity 参与</li></ul><p>当然,通用编程语言都是图灵完备的,都可以被用于构建上面的设想,因此,Verse 语言并不是必要的,但是,Tim、SPJ 都觉得目前的语言不够好,不足以方便地实现这样的未来,他们希望能有一个新语言成为元宇宙时代的标准(就像 Web 时代的 JS 一样),估计这也是为什么这个语言要叫 Verse。Verse 语言有如下的愿景:</p><ul><li>可伸缩,能够让数百万素不相识的开发者进行编写,支持数十亿用户去使用他们的产品</li><li>从一开始就包含事务化的能力,这是在百万开发者之间进行并发处理的唯一合理方案</li><li>保障跨时间的强交互性,即在编译期就确保模块包含了之前版本的 API</li><li>对初学者和专家都足够友好</li><li>可扩展,语言机制会随时间扩展,但不会让之前的代码失效</li></ul><p>在元宇宙中,大家实现的不是一个简单的独立产品,而是会对整个虚拟世界产生切实影响的世界组件,想象一下,如果在《头号玩家》那样的虚拟世界中,开发者发布了一个不前向兼容的 API,导致一堆依赖方的交互都突然失效,这将导致怎样的后果。虽然现在谈论这样的未来似乎显得为时尚早,但从中可见 Verse 的愿景背后巨大的野心。虽然元宇宙的火热主要是一场投机分子的狂欢,但不得不承认它本身是对人类未来生活方式的宏大想象。不管 Verse 语言是否真能实现它的愿景,我们还是应当对这样切实的探索抱有尊敬的心情。</p><h2 id=verse-语言的特点>Verse 语言的特点
<a href=#verse-%e8%af%ad%e8%a8%80%e7%9a%84%e7%94%b1%e6%9d%a5 class=h-anchor aria-hidden=true>#</a></h2><p>Verse 是 Epic 开发的新编程语言,由 Haskell 圈的大佬 SPJ 主导开发。</p><p>我们知道,UE 本身使用 C++ 开发,也允许使用 C++ 来对引擎进行扩展,在引擎内部也提供了蓝图作为官方的可视化编程语言。另外,随着用户群体的扩大,市面上也出现了诸如 puerts、unlua 等第三方的脚本语言方案,可以说生态上已经比较完备了。那为什么此时 Epic 还要再发明一个新的语言呢?</p><p>关于这个问题,SPJ 在 Haskell eXchange 上做过一个<a href="https://www.youtube.com/watch?v=832JF1o7Ck8">分享</a>,提到了其中的原因。Epic 的老板 Tim Sweeney 经常在鼓吹元宇宙(Metaverse),在他看来,元宇宙有如下的特点:</p><ul><li>人们可以在一个共享实时 3D 模拟世界中进行社交互动</li><li>这个世界中有一个开放的经济体系,这个体系有规则但没有某些企业作为霸主</li><li>这个世界是一个对所有程序员、艺术家、设计师开放的创作平台,而不是一个封闭的花园</li><li>这个世界不是由一堆编译好的分离的应用集合而成,所有人的代码和内容都能互操作,都能实时动态地更新代码</li><li>标准是普遍开放的,不被 Unreal 独占,也能使用其他的引擎如 Unity 参与</li></ul><p>当然,通用编程语言都是图灵完备的,都可以被用于构建上面的设想,因此,Verse 语言并不是必要的,但是,Tim、SPJ 都觉得目前的语言不够好,不足以方便地实现这样的未来,他们希望能有一个新语言成为元宇宙时代的标准,估计这也是为什么这个语言要叫 Verse。</p><p>下图是 Verse 语言希望在元宇宙中的位置,可以看到在这个设想里,Verse 在元宇宙中的地位就是 WWW 中的 Javascript 的地位:</p><p><img src=/images/2023-04-01-07-23-17.png alt></p><p>Verse 语言有如下的愿景:</p><ul><li>可伸缩,能够让数百万素不相识的开发者进行编写,支持数十亿用户去使用他们的产品</li><li>从一开始就包含事务化的能力,这是在百万开发者之间进行并发处理的唯一合理方案</li><li>保障跨时间的强交互性,即在编译期就确保模块包含了之前版本的 API</li><li>对初学者和专家都足够友好</li><li>可扩展,语言机制会随时间扩展,但不会让之前的代码失效</li></ul><p>在元宇宙中,大家实现的不是一个简单的独立产品,而是会对整个虚拟世界产生切实影响的世界组件,想象一下,如果在《头号玩家》那样的虚拟世界中,开发者发布了一个不前向兼容的 API,导致一堆依赖方的交互都突然失效,这将导致怎样的后果。虽然现在谈论这样的未来似乎显得为时尚早,但从中可见 Verse 的愿景背后巨大的野心。虽然元宇宙的火热主要是一场投机分子的狂欢,但不得不承认它本身是对人类未来生活方式的宏大想象。不管 Verse 语言是否真能实现它的愿景,我们还是应当对这样切实的探索抱有尊敬的心情。</p><h2 id=verse-语言的特点>Verse 语言的特点
<a href=#verse-%e8%af%ad%e8%a8%80%e7%9a%84%e7%89%b9%e7%82%b9 class=h-anchor aria-hidden=true>#</a></h2><p>前面提到,Verse 的作者 SPJ 是 Haskell 圈的大佬,这语言自然也有种理论照进现实的感觉,在 <a href=https://dev.epicgames.com/documentation/en-us/uefn/verse-language-reference>Verse Language Reference 文档</a>中总结了其特点有下面这些:</p><ul><li>静态强类型检查以尽可能避免未捕获的错误</li><li>支持多种编程范式,例如函数式、面向对象、命令式</li><li>所有语句都是表达式,因此所有语句都会产生一个值</li><li>代码执行失败是一种控制流</li><li>内置的事务化能力,允许用户在失败上下文中进行推测执行,如果执行失败,则表达式产生的作用都不会被提交</li><li>语言层面的并发能力</li></ul><p>在 SPJ 的<a href="https://www.youtube.com/watch?v=832JF1o7Ck8">分享</a>中,他自己总结了 Verse 语言的特点,不过从目前发布的 Verse 语言来看,和他当时说的有一些出入,这里并不是太确定这是内部实现进行了二次封装还是设计本身有改动,下文还是以实际发布的 Verse 语言为准。</p><h2 id=verse-语言部分特点介绍>Verse 语言部分特点介绍
<a href=#verse-%e8%af%ad%e8%a8%80%e9%83%a8%e5%88%86%e7%89%b9%e7%82%b9%e4%bb%8b%e7%bb%8d class=h-anchor aria-hidden=true>#</a></h2><p>对于较为完整的语言特性概览,可以参考 Epic 提供的 <a href=https://dev.epicgames.com/documentation/en-us/uefn/verse-language-quick-reference>Verse Quick Reference 文档</a>。在这里仅聊一下 Verse 里个人感觉比较特别的设计,方便让各位对 Verse 提起一点兴趣。</p><h3 id=失败控制流>失败控制流
<a href=#%e5%a4%b1%e8%b4%a5%e6%8e%a7%e5%88%b6%e6%b5%81 class=h-anchor aria-hidden=true>#</a></h3><p>大多数语言使用布尔值 <code>true</code><code>false</code> 来改变程序执行流,例如在 C++ 中,我们会这样做:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-cpp data-lang=cpp><span style=display:flex><span><span style=color:#66d9ef>if</span> (index <span style=color:#f92672>&gt;=</span> <span style=color:#ae81ff>0</span> <span style=color:#f92672>&amp;&amp;</span> index <span style=color:#f92672>&lt;</span> vec.size()) {
Expand All @@ -23,7 +23,17 @@
</code></pre></li><li><code>not</code> 运算符的操作对象<pre tabindex=0><code class=language-verse data-lang=verse>not expression
</code></pre></li><li><code>or</code> 运算符的左操作对象<pre tabindex=0><code class=language-verse data-lang=verse>expression1 or expression2
</code></pre></li><li><code>option</code> 类型的初始化表达式<pre tabindex=0><code class=language-verse data-lang=verse>option{expression}
</code></pre></li></ul><p>Verse 语言没有提供抛出异常的能力,也没有提供类似 Golang 的 <code>error</code> 或 Rust 的 <code>Result</code> 那样的通用错误表示方式,而是通过失败控制流来影响程序的执行过程。从直观来看,能更好地将错误处理融入到正常的程序执行过程中,但这似乎也使得我们很难在一个地方统一处理错误,语言提供的统一操作只有 <code>option</code> 用于表示一个值有没有,具体这个方案能力是否足够可能还需要再多使用后再做评价。</p><h3 id=事务化能力>事务化能力
</code></pre></li></ul><p>你可能会问,如果这样设计,<code>if</code> 表达式中的条件判断不就有不同的情况了么?有可能是可失败表达式,也有可能是简单的数值比较例如 <code>A &lt; B</code> 。其实在 Verse 里,普通的比较也是一个可失败的表达式,对于 <code>A &lt; B</code> 而言,当 <code>A</code> 小于 <code>B</code> 时成功,否则失败。类似地,判断一个逻辑值(类似布尔值)是否为 <code>true</code> 使用 <code>A?</code> 的形式,这也是一个可失败的表达式,当 <code>A</code><code>true</code> 的时候成功,当 <code>A</code><code>false</code> 的时候失败。所以说,Verse 确实是将失败作为一个控制流。</p><p>Verse 语言没有提供抛出异常的能力,也没有提供类似 Golang 的 <code>error</code> 或 Rust 的 <code>Result</code> 那样的通用错误表示方式,而是通过失败控制流来影响程序的执行过程。从直观来看,能更好地将错误处理融入到正常的程序执行过程中,但这似乎也使得我们很难在一个地方统一处理错误,语言提供的统一操作只有 <code>option</code> 用于表示一个值有没有,具体这个方案能力是否足够可能还需要再多使用后再做评价。不过这里可以提一个有意思的案例,看一下这个设计带来的一些强大能力。下面的 <code>for</code> 循环表达式想要实现一个扫雷游戏的逻辑,在扫雷游戏中,需要计算一个格子的邻接地雷数量,此时需要遍历整个地图的二维表,对于每一个格子,还需要遍历其周围 8 个格子,根据当前格子的位置,我们需要遍历的格子数量还不一样,例如对于角落的格子,我们只需要遍历周围三个格子即可,这样的逻辑判断写起来还是非常麻烦易错的,但在 Verse 中,这个实现却非常简单清晰:</p><pre tabindex=0><code class=language-verse data-lang=verse>for:
Y-&gt;CellRow : Cells
X-&gt;Cell : CellRow
AdjacentX := X-1..X+1
AdjacentY := Y-1..Y+1
AdjacentCell := Cells[AdjacentX][AdjacentY]
Cell &lt;&gt; AdjacentCell
AdjacentCell.Mined?
do:
set Cell.AdjacentMines += 1
</code></pre><p>首先,Verse 支持类似 range for loop 的语法,可以用 <code>X : Arr</code> 的形式遍历数组,同时支持用 <code>Index->Elem : Arr</code> 的形式在遍历数组时获取其下标,前两行就是在遍历所有地图中的格子。然后 Verse 支持 <code>X := Start..End</code> 的形式遍历一个数字 range,第三第四行就是获取当前格子周围格子的下标,这里包括了自己,因此在第六行进行判断(Verse 中 <code>&lt;></code> 表示不等于),第七行判断当前邻接的格子是否有地雷,如果有,就对当前格子的邻接地雷数 <code>+1</code>。这里最有意思的是第五行获取邻接格子的时候,这里我们完全没有考虑下标越界的情况,但程序能正确执行,这是因为数组下标访问是一个可失败的表达式,同时,<code>for</code> 循环的条件校验是一个可失败上下文,且这个上下文只对当次循环生效,也就是说,只要条件校验区域这里发生任何失败,当次循环就会跳过,因此这里完全不需要检查下标是否越界,只要越界,就不会执行 for body 中的代码。另外,如之前所述,这里的 <code>&lt;></code><code>?</code> 也是可失败表达式。这里的语义并不是判断他们是否相等而决定是否循环,而是他们是否相等决定了表达式是否成功,失败的时候就不执行 for body 了。这是不是非常有意思。</p><h3 id=事务化能力>事务化能力
<a href=#%e4%ba%8b%e5%8a%a1%e5%8c%96%e8%83%bd%e5%8a%9b class=h-anchor aria-hidden=true>#</a></h3><p>在上一节中,我们了解到 Verse 语言有一个可失败上下文的概念,并了解到带有 <code>&lt;decides></code> 说明符的函数的函数体也是一个可失败上下文。这里的 <code>&lt;decides></code> 是 Verse 的<a href=https://dev.epicgames.com/documentation/en-us/uefn/specifiers-and-attributes-in-verse>说明符</a>之一,说明符分为四种:</p><ul><li>类说明符,例如 <code>&lt;abstract></code> 标注一个类是抽象类</li><li>访问说明符,例如 <code>&lt;public></code> 标注类成员可以被公开访问</li><li>作用说明符,例如 <code>&lt;suspends></code> 标注一个函数是异步的</li><li>实现说明符,例如 <code>&lt;native></code> 说明符表示对应 API 是 C++ 实现的</li></ul><p>作用说明符本身又被分为两种:</p><ul><li>独占说明符:可以存在一个或不存在,如果不存在,默认情况下是 <code>&lt;no_rollback></code></li><li>附加说明符:可以存在任意个</li></ul><p><code>&lt;decides></code> 是一个附加说明符,用于标记函数出错时自动回滚,它必须和独占说明符 <code>&lt;transacts></code> 同时出现。<code>&lt;transacts></code> 表示函数执行的任何操作都可以回滚。举例而言,下面的 <code>IncScore</code> 就是被标注了可自动回滚:</p><pre tabindex=0><code class=language-verse data-lang=verse>var MyScore : int = 100

IncScore(Arr: []int)&lt;decides&gt;&lt;transacts&gt;: void =
Expand Down

0 comments on commit d01b93b

Please sign in to comment.