今天你 Emo 了没?

向下滚动,认识 Emo

Emo

语法简洁·显式定义·符合直觉

一门国产系统级编程语言。从原生可执行文件到 WebAssembly, 从 BEAM 虚拟机到裸机内核 —— 一门语言,贯通整个系统栈。

当前版本:v0.26.1024-alpha 2026 (冬至) 「立冬,十月节。冬,终也,万物收藏也。」

main.emo
// 这是一行注释
class User {
  def init(age Int64) {
    self.age = age
  }

  def adult?() Bool {
    return self.age >= 18
  }
}

const fuxi = User.new(age: 128)

emo Company {
	def can_hire?(u User) Bool {
		return u.adult?()
	}
}

const can_hire = Company.can_hire?(fuxi)
var result = if can_hire { "能啊" } else { "肯定不行" }

println("这人能要吗?${result}")

编译目标

一门语言,五个目标

同一份 Emo 代码,可以编译到系统栈的每一层 —— 写应用、写服务、写前端,一直写到操作系统内核。

原生可执行文件 单文件,免安装 WebAssembly 浏览器与 WASI TypeScript 编译到其他语言 BEAM 虚拟机 Erlang 生态 RISC-V 裸机运行于 QEMU

核心特色

为清晰而生

Emo 汲取三十年开源编程语言的经验与教训,围绕三条原则设计:表达力强的语法、最少惊讶原则、多编译目标。

◆明确的语法

调用一定带括号,return 一定写出来,代码块只有一种形状。一切所见即所得,解析器与读者都不必猜测。

◆渐进式类型

运行时动态类型,编译期静态检查。函数签名必写类型,其余交给推断;类型信息还会反哺原生代码的性能。

◆默认不可变

const / var 分层明确,类实例是值类型;长期可变状态只住在 Box 里,且永远不跨越进程边界。

◆Actor 并发

do 起进程,<- 发消息,receive 收信箱。崩溃隔离与监管内建,无共享内存原语。

◆直接风格网络

没有 async/await,没有函数染色。任何函数都能做 IO,调度器在 io_uring / kqueue / IOCP 之上切换进程。

◆结构化模块

目录树即模块树:没有 import / export,路径即引用,internal/ 的可见性由编译器强制。

◆自带包管理

require 引入依赖,精确版本 + MVS 解析,构建即安装;中心注册表支持私有部署。

◆配置即代码

Emo 就是自己的配置语言:受限 Profile 保证终止、密封、无副作用,不再需要第二种 Schema 语言。

◆C 互操作

foreign def 一行声明即可链接 C 库;OCaml 5 实现,一流的 C FFI 直通原生后端。

并发

进程与消息传递,Actor 模型的嫡系

Emo 的并发围绕进程与消息传递构建,直接映射 BEAM 进程; 原生后端则以 OCaml 5 effects 实现调度器 —— 与 Eio 同源的地基。

  • 消息传递是唯一核心原语,共享内存不在语义之内
  • 尾调用有保证,递归就是收信循环的惯用形态
  • 未处理的错误只杀死出错的进程,监管策略交给库
pipeline.emo
// 三个进程, 一条消息链
def doubler(next Pid) Int64 {
  receive {
    (i, n) -> {
      next <- (i, n * 2)
      return doubler(next)
    }
    "done" -> {
      next <- "done"
      return halt()
    }
  }
}

def labeler(count Int64, boss Pid) Int64 {
  receive {
    (i, n) -> {
      println("订单 ${i}: ${n} 件")
      return labeler(count + 1, boss)
    }
    "done" -> {
      boss <- (self_pid(), count)
      return halt()
    }
  }
}

def feed(line Pid, i Int64) Int64 {
  if i > 3 {
    line <- "done"
    return 0
  }
  line <- (i, i)
  return feed(line, i + 1)
}

const lab = do labeler(0, self_pid())
const line = do doubler(lab)
feed(line, 1)

receive {
  (who, handled) -> { println("处理了 ${handled} 个订单") }
}
greeter.emo
// 接口属于调用方: 形状匹配即满足, 无需 implements
interface Greeter {
  def greet() String
}

class Machine {
  def greet() String {
    return "[beep] 你好"
  }
}

class Friend {
  def greet() String {
    return "很高兴见到你"
  }
}

def welcome(g Greeter) String {
  if g.is(Machine) {
    return "一台机器说: ${g.greet()}"
  }
  return "一位朋友说: ${g.greet()}"
}

println(welcome(Machine.new()))
println(welcome(Friend.new()))

抽象

结构化接口,零成本多态

interface 声明一组方法签名,任何形状匹配的类都自动满足 —— 不需要 implements。接口属于调用方,实现方甚至不必知道接口存在。

  • 编译期校验形状,运行时鸭子分派,零开销
  • 没有继承 —— 复用靠组合、鸭子类型与接口
  • g.is(Machine) 为真后,g 自动收窄类型

EmoUI 规划中

UI 就是普通的 Emo 代码

EmoUI 是用 Emo 写的组件式 UI 框架:没有模板语言, 组件树就是带代码块的嵌套调用。Emo 的语法正是为它塑形。

  • 组件即函数,Props 由内置类型检查器把关
  • UI 事件即进程消息 —— 天然长成 Elm 架构
  • 响应式原语显式可预测,编译器把可静态确定的更新编译成定向刷新
home_page.emo
// 没有模板语言 —— UI 就是普通的 Emo 代码
page(title: "首页") {
  navbar() {
    logo()
    menu(routes)
  }

  list(users) -> (user User) {
    card(user) {
      text(user.name)
      text(user.bio)
    }
  }
}
kernel.emo
// kernel_main.emo — RISC-V 目标: 无 OS, 无 libc
//
//   emo build kernel_main.emo --target riscv64 -o kernel.img
//   qemu-system-riscv64 -kernel kernel.img

def kernel_main() {
  uart.write_line("hello from EmoOS")

  // 显式内存原语: 危险的操作, 看起来就危险
  const status = peek(uart_status_addr)
  poke(uart_data_addr, status)
}

EmoOS 规划中

一门能写内核的语言

Emo 的边界一直延伸到操作系统层:RISC-V 编译目标面向裸机, 无 OS、无 libc、无默认运行时,直接产出 QEMU 可引导镜像。

  • 分层核心库:内核代码只用零依赖的 core
  • 内存原语显式命名 —— 危险的操作看起来就危险
  • GC、分配器、调度器可替换;内核编译到 RISC-V,Shell 与应用留在原生目标 —— 一门语言贯通系统两侧

现在就开始用 Emo

开源、MIT 协议、由 OCaml 5 实现的参考编译器。读一遍语言漫游,十分钟看懂整门语言。