备份语言规范、顶级类型与运行时设计草稿
This commit is contained in:
@@ -4,7 +4,9 @@
|
||||
|
||||
## 独立代码段
|
||||
|
||||
代码分别存储为独立代码段,每段关联一个归属 workspace 和至少一级 namespace。S3 承担代码内容的存储职责,索引维护 namespace key 与代码段的成员关系;编写或修改代码的用户身份另行记录。
|
||||
代码分别存储为独立代码段,以资源 ID 识别并关联归属 workspace。S3 承担代码内容的存储职责,索引维护 namespace key 与代码段的成员关系;一段代码可以具有多个命名入口,编写或修改代码的用户身份另行记录。
|
||||
|
||||
移除 namespace 成员入口不删除仍被其他保留程序引用的代码段。资源 ID、存储对象键与 namespace key 分别表达逻辑身份、存储位置和命名入口,具体引用语义见[资源引用](../guide/07-top-level-types/references.md)。
|
||||
|
||||
源码文件不作为代码身份或 module 边界。本书中的 Markdown 文件是文档章节,不对应语言中的源码组织单位。
|
||||
|
||||
@@ -31,7 +33,7 @@ S3 对象键不是语言中的 namespace key。bucket 名、对象键和存储
|
||||
|
||||
## namespace 制
|
||||
|
||||
namespace 同时表达归属与查找位置,使业务函数、类型、界面逻辑和 agent 定义遵循一致的组织模型。第一级与后续层级具有相同语义。
|
||||
namespace 提供归属 workspace 内的组织与查找位置,使业务函数、类型、界面逻辑和 agent 定义遵循一致的组织模型。第一级与后续层级具有相同语义。
|
||||
|
||||
基础内容也纳入资源归属方向,但本附录的 S3 代码段约定不自动规定媒体、GIS 数据、对象或 agent 记忆的存储后端。代码视图与完整资源集合的区别见[namespace](../guide/03-namespaces.md)。
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
# 形式文法
|
||||
|
||||
本附录集中列出正文采用的文法草案。文法说明可表达的源码结构;名称、类型、可见性与执行效果由相应章节定义。各主题的确定程度见[规范状态](specification-status.md)。
|
||||
本附录集中列出文法草案。文法说明可表达的源码结构;名称、类型、可见性与执行效果遵守相应语义约束。各主题的确定程度见[规范状态](specification-status.md)。
|
||||
|
||||
[对象类型与构造](../guide/07-top-level-types/README.md)采用候选的自身类型标注、trait、容器、任务及 Agent 实例记法。以下 EBNF 只覆盖列出的语法范围,不穷尽对象构造形式。
|
||||
|
||||
Object 是继承根,Object 和 Type 都是 Type 的实例,Type 继承 Object。实例化线与继承线属于类型语义;typeOf、basesOf 等反射接口与显式继承语法仍待定义。
|
||||
|
||||
class、agent 等构造入口自身是对象。以下产生式中的文字终结符描述候选构造记法,不据此将这些名称定为保留关键字;入口的类型、名称解析及调用语法尚待定义。
|
||||
|
||||
## EBNF 记法
|
||||
|
||||
@@ -97,7 +103,7 @@ primary = identifier | string | number | symbol
|
||||
| "(", expression, ")" ;
|
||||
```
|
||||
|
||||
成员访问与调用先于一元负号,一元负号先于乘除,乘除先于加减。正文采用同级二元算术运算从左到右组合的规则。
|
||||
成员访问与调用先于一元负号,一元负号先于乘除,乘除先于加减。同级二元算术运算从左到右组合。
|
||||
|
||||
此处能表达成员调用,不代表某个类型自动拥有相应成员。数据读取提案使用同一套表达式文法,没有单独的 get 关键字。
|
||||
|
||||
|
||||
@@ -0,0 +1,468 @@
|
||||
# 框架如何接管代码执行
|
||||
|
||||
框架通过保存定义、关联入口、管理活动状态和调用用户函数来组织执行。语言、执行引擎、宿主和框架的职责分别说明,才能判断一段代码何时运行、在哪运行,以及哪个实体一直存续。基础结构见[12 门语言的执行模型与生命周期](language-runtime-lifecycles.md),词法用途见[关键词手册](language-keywords.md)。
|
||||
|
||||
资料核对日期:2026-10-13。本文以普通 hosted C 进程、CPython/FastAPI/ASGI、Java/Spring Boot/Spring MVC、Unity 6.0,以及 TypeScript/React/Node/Chromium 的指定路径为案例。持续更新的官方文档与实现源码用于说明相应机制,不代表所有历史版本。代码展示预期行为,未作为执行日志;框架的开发模式、配置和替代后端会改变部分时序。
|
||||
|
||||
## 先确定每一层回答什么
|
||||
|
||||
| 层 | 职责 | 典型证据 |
|
||||
| --- | --- | --- |
|
||||
| 语言 | 调用、作用域、暂停、异常、类型等的语义 | Python、Java、C#、ECMAScript 等规范 |
|
||||
| 编译或构建工具 | 检查和转换源码,准备可执行逻辑 | TypeScript 类型擦除、JSX 转换、C# 编译 |
|
||||
| 执行引擎或原生执行环境 | 推进当前代码并维护必要执行状态 | CPython、JVM、V8、Mono、原生机器码 |
|
||||
| 宿主 | 应用入口、I/O、系统事件、线程或事件循环、呈现能力 | ASGI 服务器、Servlet 容器、Node、浏览器、Unity |
|
||||
| 库或框架 | 入口映射、应用状态、组件或请求的组织 | FastAPI 路由、Spring bean、React 组件树 |
|
||||
|
||||
这些是职责边界,不要求每层都是一个独立进程,也不保证每个产品只处在一层。Unity 同时提供引擎宿主与组件管理;Node 包含 V8、原生绑定及 libuv 等协作部分;浏览器还有渲染、网络及多进程组织,不能缩减成 V8 本身。
|
||||
|
||||
注册建立“条件与逻辑”的关系。外部事件或明确调用进入入口;调度机制安排执行机会;引擎执行本次函数。框架也会执行自己的代码,它调用用户函数时通常仍使用语言的普通调用机制。
|
||||
|
||||
## 路径一:C 普通进程
|
||||
|
||||
### 从启动到返回
|
||||
|
||||
这是一个完整的 hosted C 示例,不依赖应用框架。预期输出 `42` 并正常返回成功状态。
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
|
||||
static int price(int base) {
|
||||
return base + 2;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int result = price(40);
|
||||
printf("%d\n", result);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
```text
|
||||
启动程序
|
||||
→ 操作系统及实现的启动代码准备执行环境
|
||||
→ 进入 main
|
||||
→ 用户调用 price,当前线程进入该函数
|
||||
→ price 返回 42,继续 main
|
||||
→ printf 产生输出
|
||||
→ main 正常返回,执行正常退出流程
|
||||
```
|
||||
|
||||
`price` 的函数定义不因“程序已经启动”而自己反复执行。这里没有应用任务队列:下一步由当前控制流确定;CPU 最终执行编译后的指令,OS 仍可调度执行线程。[C23 草案的 hosted 启动与终止](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf)
|
||||
|
||||
### 谁持有状态
|
||||
|
||||
| 实体 | 保存的信息 | 结束方式 |
|
||||
| --- | --- | --- |
|
||||
| 程序及静态存储 | 可执行代码与长期数据 | 正常退出或进程终止 |
|
||||
| `main` 调用 | `result`、当前进度及调用关系 | 返回 |
|
||||
| `price` 调用 | `base` 及临时计算 | 返回 42;典型原生调用状态结束 |
|
||||
| 输出设施 | 缓冲和 OS 资源 | 库及退出协议处理 |
|
||||
|
||||
实际 ABI 可以用栈、寄存器和内联等实现调用。语言规定调用结果,具体执行布局由实现决定。添加 GUI 库或 HTTP 服务器后,入口还会增加库管理的事件关系;C 语言本身没有因此改变。
|
||||
|
||||
## 路径二:FastAPI
|
||||
|
||||
### 注册路由与处理请求是两个动作
|
||||
|
||||
以下内容是可交给 ASGI 服务器加载的 Python 模块。`sleep` 用于展示可暂停等待,不代表真实数据库实现。预期请求 `GET /price?base=40` 得到 JSON 数据 `{"price":42}`。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@app.get("/price")
|
||||
async def price(base: int = 40):
|
||||
await asyncio.sleep(0.01)
|
||||
return {"price": base + 2}
|
||||
```
|
||||
|
||||
加载模块时执行导入、创建 `app`、创建函数及应用装饰器;装饰器把路径、方法和函数等关联起来。它不在注册时替未来每个请求执行 `price` 函数体。请求进入后,框架才使用这份关联选择处理函数。
|
||||
|
||||
服务器以 Uvicorn 为例;事件循环可使用 asyncio 或其兼容实现,而非只能使用 CPython 中某个唯一固定循环。[Uvicorn 事件循环选择](https://uvicorn.dev/concepts/event-loop/)
|
||||
|
||||
### 一次请求经过哪些层
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as 客户端
|
||||
participant Server as ASGI 服务器与事件循环
|
||||
participant App as FastAPI 与 Starlette
|
||||
participant Handler as 用户 price 协程
|
||||
Client->>Server: GET /price?base=40
|
||||
Server->>App: 调用应用:scope、receive、send
|
||||
App->>App: 路由、参数与依赖处理
|
||||
App->>Handler: 调用并推进协程
|
||||
Handler->>Server: 可暂停等待
|
||||
Note over Handler: 局部状态和继续关系被保留
|
||||
Server->>Handler: 条件满足后安排继续
|
||||
Handler-->>App: 返回字典
|
||||
App->>Server: 生成并发送响应事件
|
||||
Server-->>Client: HTTP JSON 响应
|
||||
```
|
||||
|
||||
图示压缩了中间件和序列化细节。ASGI 的 HTTP `scope` 对应一次请求,WebSocket `scope` 则可贯穿整个连接;HTTP keep-alive 不把多个请求合并为同一次处理函数调用。服务器提供协议事件,应用通过可等待的 `receive`/`send` 接收与发送。[ASGI 规范](https://asgi.readthedocs.io/en/latest/specs/main.html)
|
||||
|
||||
| 结构 | 保存的信息 | 管理者与存续 |
|
||||
| --- | --- | --- |
|
||||
| 模块及 `app`、路由定义 | 应用配置和入口映射 | 模块/框架,跨多个请求 |
|
||||
| 请求 scope、Request、依赖求值状态 | 方法、路径、头、输入及本次依赖 | 服务器/Starlette/FastAPI,围绕请求 |
|
||||
| coroutine 继续状态 | `base` 等局部状态、等待后的进度 | Python 执行机制,围绕本次处理 |
|
||||
| Task 及事件循环的等待管理 | 活动状态、等待结果和恢复安排 | ASGI 服务器选定的异步环境 |
|
||||
| 响应对象与输出事件 | 状态码、头及 body | 框架/服务器,直至相应发送流程结束 |
|
||||
|
||||
### 同步函数和异步函数的执行位置
|
||||
|
||||
FastAPI 通过框架调用的普通 `def` 路由函数和同步依赖,通常交给外部线程池;`async def` 路由在异步调用链中推进。这个区别只适用于它负责调用的设施:用户自己在 async 路由中直接调用普通辅助函数,仍是普通同步调用,不自动被挪到线程池。异步函数中的 CPU 循环或阻塞 I/O 仍能阻碍事件循环。[FastAPI 的技术说明](https://fastapi.tiangolo.com/async/#very-technical-details)
|
||||
|
||||
### 应用、请求和依赖分别清理
|
||||
|
||||
应用的 `lifespan` 上下文管理共享资源:进入部分用于应用接收请求前的准备,退出部分用于关闭。带 `yield` 的依赖围绕更小的工作范围获取和释放资源。当前文档区分 `scope="function"` 的函数退出清理与 `scope="request"` 的响应发送后清理;不要把两者写成一个固定时间点。[应用 lifespan](https://fastapi.tiangolo.com/advanced/events/)、[带 yield 依赖的 scope](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/#early-exit-and-scope)
|
||||
|
||||
处理函数返回不意味着应用退出;请求结束不意味着共享连接池必须销毁。失败进入异常处理路径,取消及断连的传播要结合服务器、中间件和被等待操作判断,不能承诺客户端断开后所有业务效果立即停止或回滚。
|
||||
|
||||
## 路径三:Spring Boot
|
||||
|
||||
### 从入口启动容器
|
||||
|
||||
基线是使用 Spring MVC 的应用及嵌入式 Servlet 容器,Tomcat 可作为例子。Spring Boot 组织启动与配置;Spring 的 `ApplicationContext` 管理 bean;Servlet 容器接入 HTTP;JVM 执行 Java 方法。这些不是同一个生命周期。
|
||||
|
||||
下面是 `example.pricing` 包中的 `PriceApplication.java` 示例,前提是项目具有相应 Spring Boot Web 依赖。预期请求 `GET /price?base=40` 返回包含 `price: 42` 的 JSON 对象。
|
||||
|
||||
```java
|
||||
package example.pricing;
|
||||
|
||||
import java.util.Map;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@SpringBootApplication
|
||||
public class PriceApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(PriceApplication.class, args);
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class PriceController {
|
||||
@GetMapping("/price")
|
||||
public Map<String, Integer> price(
|
||||
@RequestParam(name = "base", defaultValue = "40") int base) {
|
||||
return Map.of("price", base + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
启动时由容器读取配置、发现并创建所需 bean、注入依赖及调用相应初始化设施。映射注解是供框架使用的元数据;Java 的 `@GetMapping` 拼写不是新增 Java 关键词,声明它也不等于马上处理请求。[Spring Boot 的启动](https://docs.spring.io/spring-boot/reference/features/spring-application.html)、[bean 与依赖注入](https://docs.spring.io/spring-boot/reference/using/spring-beans-and-dependency-injection.html)
|
||||
|
||||
### 请求怎样进入 controller
|
||||
|
||||
```text
|
||||
HTTP 请求
|
||||
→ Servlet 容器接入并安排处理
|
||||
→ Filter 等链路
|
||||
→ DispatcherServlet
|
||||
→ HandlerMapping 查找匹配的处理器
|
||||
→ HandlerAdapter 配合参数解析等设施调用 controller 方法
|
||||
→ JVM 推进本次 Java 调用
|
||||
→ 返回值处理及消息转换形成 JSON 响应
|
||||
→ 容器写回客户端
|
||||
```
|
||||
|
||||
这里选择 `@RestController` 的数据响应路径;返回视图名的 controller 还会涉及视图解析。URL 没有一个“执行 Java”的特殊开关,服务端配置的分派逻辑决定产生响应的方法。[DispatcherServlet](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-servlet.html)、[请求处理序列](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-servlet/sequence.html)
|
||||
|
||||
| 结构 | 保存的信息 | 管理者与存续 |
|
||||
| --- | --- | --- |
|
||||
| JVM 的类、方法元数据 | 编译后的 Java 逻辑 | JVM/类加载器 |
|
||||
| bean definition 与 ApplicationContext | 创建配方、依赖关系及受管理实例 | Spring,跨请求或按配置的 scope |
|
||||
| 请求映射与 handler 元数据 | 路径、方法、参数及调用入口 | Spring MVC,跨请求 |
|
||||
| Servlet 请求/响应及分派状态 | 本次 HTTP 数据和处理关联 | 容器及框架,围绕一次请求 |
|
||||
| JVM 方法 frame | 参数、局部变量及方法进度 | 本次 Java 调用 |
|
||||
|
||||
默认 singleton bean 在容器内被复用,不是每个请求都创建一个 controller。方法 frame 是本次调用的状态;把请求数据存入复用实例字段会涉及并发访问。这是实例存续与请求存续不同带来的后果。prototype 等 scope 的退出管理也有不同保证,不能认为所有 bean 都由容器完整管理至销毁。[Spring bean scope](https://docs.spring.io/spring-framework/reference/core/beans/factory-scopes.html)
|
||||
|
||||
### 初始化、请求返回与关闭
|
||||
|
||||
Spring 可以调用 `@PostConstruct`、初始化接口或配置的 init 方法;正常关闭时可调用 `@PreDestroy` 等销毁设施。`Lifecycle`/`SmartLifecycle` 还表达受管理活动的启停。回调由容器在相应条件下调用,不由 Java GC 替代;具体 bean scope 的管理保证需要分别核对。[Spring bean 生命周期](https://docs.spring.io/spring-framework/reference/core/beans/factory-nature.html)
|
||||
|
||||
请求方法返回后应用继续存续。Boot 的正常退出支持关闭 ApplicationContext 的安排;强制终止不能被当作所有清理钩子都会执行的正常关闭。[Spring Boot 应用退出](https://docs.spring.io/spring-boot/reference/features/spring-application.html#features.spring-application.application-exit)
|
||||
|
||||
### WebFlux 是另一种请求模型
|
||||
|
||||
Spring Boot 并不只代表 Servlet 阻塞模型。WebFlux 使用非阻塞契约、响应式组合及服务器适配;通常用较少的事件循环工作线程推进活动,和 MVC 常见的阻塞处理假设不同。`Mono`/`Flux` 保存或组合数据流协议,不等同于每个请求专属的一条 JVM 调用栈。这里的 Reactor `Mono` 是响应式库类型,与 Unity 的 Mono 执行后端无关。MVC 也能使用异步设施,不能把二者概括成“Java 一定阻塞”和“Java 一定事件循环”。[Spring WebFlux 的并发模型](https://docs.spring.io/spring-framework/reference/web/webflux/new-framework.html)
|
||||
|
||||
## 路径四:Unity
|
||||
|
||||
### 执行后端与阶段安排是两个问题
|
||||
|
||||
Unity 的 C# 脚本通常先编译为 IL 等内容。Mono 后端提供托管执行与 JIT;IL2CPP 将 IL 转为 C++ 再编译为原生代码。不能直接把 Unity 写成桌面 CoreCLR 应用。无论采用哪条后端路径,引擎依然承担场景与组件管理,以及 PlayerLoop 的阶段调用安排。[Unity 脚本后端](https://docs.unity3d.com/6000.0/Documentation/Manual/scripting-backends.html)
|
||||
|
||||
```text
|
||||
开发准备:C# 源码 → IL → Mono 执行路径/IL2CPP 原生编译路径
|
||||
|
||||
应用运行:Unity 启动与场景准备
|
||||
→ 建立 GameObject 与组件实例及关系
|
||||
→ 根据对象活动、组件启用与阶段规则调用事件函数
|
||||
→ PlayerLoop 推进输入、物理、脚本更新及其他系统
|
||||
→ 场景卸载、禁用或销毁触发相应处理
|
||||
```
|
||||
|
||||
PlayerLoop 是引擎的一组系统阶段,还能通过相关 API 定制;并不是每一帧把项目里所有 C# 函数都运行一次。[Unity 事件执行顺序](https://docs.unity3d.com/6000.0/Documentation/Manual/execution-order.html)
|
||||
|
||||
### 哪些回调在什么条件下进入
|
||||
|
||||
| 入口 | 管理条件 | 不能推出的结论 |
|
||||
| --- | --- | --- |
|
||||
| `Awake` | 组件实例加载、对象激活等符合条件的初始化,一实例调用一次 | 不是所有不活动对象都在场景加载时立即执行,也不是 C# 普通构造器 |
|
||||
| `OnEnable` | 对象活动且组件启用时 | 不是一生只调用一次,可因再次启用进入 |
|
||||
| `Start` | 启用后首次更新前的一次初始化 | 不保证与 Awake 同帧;禁用时可能延后 |
|
||||
| `FixedUpdate` | 固定时间步的物理更新安排 | 每个显示帧可能零次、一次或多次 |
|
||||
| `Update` | 符合条件的脚本帧更新 | 不是全部数据对象的通用钩子 |
|
||||
| `LateUpdate` | 在 Update 后的相应阶段 | 不代替任意线程的同步协议 |
|
||||
| `OnDisable` | 组件或对象退出启用活动等相应情形 | 禁用和销毁不是同一状态 |
|
||||
| `OnDestroy` | 满足条件的组件或对象销毁 | 有适用边界;强制退出不能保证执行 |
|
||||
|
||||
条件详见 [Awake](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.Awake.html)、[OnEnable](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.OnEnable.html)、[Start](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.Start.html)、[FixedUpdate](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.FixedUpdate.html)、[Update](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.Update.html)、[LateUpdate](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.LateUpdate.html)、[OnDisable](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.OnDisable.html)、[OnDestroy](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.OnDestroy.html)。
|
||||
|
||||
以下是应保存为 `PriceLabel.cs` 并挂在活动 GameObject 上的组件例子。这里用日志观察执行,不代表 UI 的正式绘制实现。
|
||||
|
||||
```csharp
|
||||
using UnityEngine;
|
||||
|
||||
public class PriceLabel : MonoBehaviour
|
||||
{
|
||||
private int price;
|
||||
|
||||
private void Awake() { price = 42; }
|
||||
private void OnEnable() { Debug.Log("enabled"); }
|
||||
private void Start() { Debug.Log(price); }
|
||||
private void Update() { /* 每次符合条件的更新处理 */ }
|
||||
private void OnDisable() { Debug.Log("disabled"); }
|
||||
}
|
||||
```
|
||||
|
||||
在常规初始化条件下,实例准备→Awake→OnEnable→Start→后续 Update。重新禁用再启用,可以再发生 OnEnable;这不意味着 price 字段被重新创建或 Start 再次执行。同类不同对象的调用顺序不能仅凭源码文件排列推断。
|
||||
|
||||
### 哪些状态跨帧存在
|
||||
|
||||
| 结构 | 保存的信息 | 管理者与存续 |
|
||||
| --- | --- | --- |
|
||||
| 场景、GameObject 与组件关系 | 对象组织、活动及启用状态 | Unity 引擎,跨帧 |
|
||||
| 脚本实例及字段 | `price` 等长期组件状态 | 托管对象及引擎对象关联,跨回调 |
|
||||
| 每次 Update 等的方法调用状态 | 本次局部变量和当前进度 | 执行后端,一次回调 |
|
||||
| IEnumerator 状态机与协程等待记录 | 跨 yield 的局部数据、继续位置及等待条件 | 编译器表示及 Unity 协程调度 |
|
||||
| 引擎资源与托管引用 | 场景对象、资源及引用关系 | 引擎销毁和托管回收分别处理 |
|
||||
|
||||
普通 `Update` 返回后,下帧是另一次函数调用;Unity 协程 `yield return` 后则由引擎按等待条件继续迭代状态。`StartCoroutine` 不自动创建后台线程;同步耗时计算仍可占用主线程。停止条件也取决于对象、组件及协程 API,不能把“组件 disabled”当成所有任务统一取消协议。[Unity 协程](https://docs.unity3d.com/6000.0/Documentation/Manual/Coroutines.html)
|
||||
|
||||
## 路径五:React
|
||||
|
||||
### 构建不是应用运行的中间调度层
|
||||
|
||||
```text
|
||||
开发及构建:
|
||||
TS/TSX 源码
|
||||
→ 类型检查、类型处理、JSX 转换及模块处理
|
||||
→ 供目标宿主执行的 JavaScript
|
||||
|
||||
运行:
|
||||
浏览器:启动 JS → React 组织组件计算 → DOM 提交 → 浏览器呈现
|
||||
服务器:Node 执行 JS → React 服务端渲染 → 输出 HTML 等响应
|
||||
```
|
||||
|
||||
转换可以分散在 TypeScript、其他转换器和打包工具中;JSX 也可以先被保留。构建工具运行在 Node,不证明组件随后一定在 Node 执行。React 是正在被执行的库代码,会组织用户组件及更新的调用;TS 类型通常已擦除。[TypeScript 的类型擦除](https://www.typescriptlang.org/docs/handbook/2/basic-types.html#erased-types)、[JSX 转换模式](https://www.typescriptlang.org/docs/handbook/jsx.html)
|
||||
|
||||
### 浏览器首次显示与一次点击
|
||||
|
||||
下面是客户端入口 TSX 的例子,前提是页面中有 `id="root"` 的容器,且构建环境提供 React、React DOM 和相应类型声明。它是普通客户端渲染,不含 SSR。
|
||||
|
||||
```tsx
|
||||
import { useEffect, useState } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
|
||||
function Price() {
|
||||
const [price, setPrice] = useState(42);
|
||||
|
||||
useEffect(() => {
|
||||
const previousTitle = document.title;
|
||||
document.title = `Price: ${price}`;
|
||||
return () => { document.title = previousTitle; };
|
||||
}, [price]);
|
||||
|
||||
return <button onClick={() => setPrice(p => p + 1)}>{price}</button>;
|
||||
}
|
||||
|
||||
createRoot(document.getElementById("root")!).render(<Price />);
|
||||
```
|
||||
|
||||
预期首次按钮显示 42,点击后显示 43;提交后的 Effect 同步相应标题。示例的非空断言不构成运行时容器创建,HTML 必须实际提供该节点。调用 root.render 提交渲染请求,也不能据此认为调用返回时所有 DOM 和 Effect 工作已经完成。[createRoot 与 render](https://react.dev/reference/react-dom/client/createRoot)
|
||||
|
||||
| 步骤 | 谁进入或调用 | 保存或使用的状态 |
|
||||
| --- | --- | --- |
|
||||
| 加载入口 JS | 浏览器的脚本加载与求值机制 | JS 模块、函数及 React 库 |
|
||||
| 首次 render 请求 | 入口调用 React root API | root、更新及组件关系 |
|
||||
| 组件计算 | React 调用 `Price` | 本次调用的局部值,React 持有的 Hook 状态 |
|
||||
| commit | React 调用 DOM 等宿主接口 | 已提交的树及 DOM 关系 |
|
||||
| Effect setup | React 按 Effect 规则安排 | 依赖和返回的 cleanup |
|
||||
| 用户点击 | 浏览器事件分派进入 React 事件处理,再调用用户处理逻辑 | 事件、组件关联及更新请求 |
|
||||
| 后续更新 | React 处理状态更新,再组织 render/commit | 新状态,旧依赖及新依赖 |
|
||||
| 卸载 | root 或组件树操作使组件退出 | Effect cleanup、宿主节点及关联清理 |
|
||||
|
||||
render 是计算下一份界面描述,commit 才将相应变化应用到宿主。组件函数可以被多次调用;应保持渲染计算纯净,不能把“函数被调用一次”当作“一次业务操作已经提交”的保证。[React render 与 commit](https://react.dev/learn/render-and-commit)、[组件与 Hook 的纯度要求](https://react.dev/reference/rules/components-and-hooks-must-be-pure)
|
||||
|
||||
### 状态为什么没有随组件函数返回而消失
|
||||
|
||||
React 持有组件关系及 Hook 状态,组件函数每次调用读取当前状态。普通局部变量随调用建立,`useState` 管理的状态则与 React 管理的组件身份关联,不能当作每次新建的普通局部值。[React 状态的保留与重置](https://react.dev/learn/preserving-and-resetting-state)
|
||||
|
||||
| 结构 | 职责 | 所属层 |
|
||||
| --- | --- | --- |
|
||||
| JS 函数、闭包和本次调用状态 | 执行组件计算及事件函数 | JavaScript 引擎 |
|
||||
| React element 等界面描述 | 表达本次计算所得结构 | React 库数据 |
|
||||
| Fiber 与 root | 组件工作、父子关联、已保存状态、更新及待处理工作 | React 当前协调实现 |
|
||||
| Hook 状态与 Effect 记录 | 状态、依赖及 cleanup 关联 | React 管理结构 |
|
||||
| DOM 节点与事件设施 | 浏览器中的宿主呈现及交互 | 浏览器 |
|
||||
|
||||
Fiber 是实现结构,源码包含子节点、相邻节点、更新队列和保存状态等信息。它不等于 V8 调用栈,也不是所有 React API 使用者必须直接创建的对象;字段和布局不是稳定应用 API。[React 实现中的 Fiber 类型](https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactInternalTypes.js)
|
||||
|
||||
### React Hook 与 Unity 阶段回调的差别
|
||||
|
||||
`useState`、`useEffect` 等普通 Hook 必须服从顶层调用与顺序约束,它们不是可以任意在条件中增删的动态回调列表。`useEffect` 记录的 setup/cleanup 与依赖变化关联;`useState` 则管理状态,并不代表事件监听。特殊的 `use` API 有不同的调用规则,不能用“所有 use 开头函数都绝对相同”概括。[Hook 规则](https://react.dev/reference/rules/rules-of-hooks)、[use API](https://react.dev/reference/react/use)
|
||||
|
||||
Effect 在组件提交后按相关规则同步外部系统;依赖变化时先清理旧关联,再建立新关联,卸载时清理。开发 Strict Mode 会增加用于检查的 setup/cleanup 周期。Effect 与浏览器实际绘制的先后不能简单固定为“每次 paint 之后”;`useEffect` 与 `useLayoutEffect` 的契约不同。[useEffect 的时序与边界](https://react.dev/reference/react/useEffect)
|
||||
|
||||
Unity 主要用引擎命名阶段选择符合条件的组件回调;React 主要用更新、组件计算、提交和依赖关联组织 UI。React 不要求组件每个显示帧都重新计算,也没有为每个普通函数自动提供 Awake/Update。
|
||||
|
||||
### 可选的服务端渲染与 hydration
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Browser as 浏览器进程
|
||||
participant Server as Node 服务器进程
|
||||
participant SSR as 服务器 React 渲染
|
||||
participant ClientReact as 浏览器 React
|
||||
Browser->>Server: 页面请求
|
||||
Server->>SSR: 调用服务端渲染入口
|
||||
SSR-->>Server: HTML 流等结果
|
||||
Server-->>Browser: HTTP 响应与后续资源
|
||||
Browser->>Browser: 解析 HTML 并加载客户端 JS
|
||||
Browser->>ClientReact: hydrateRoot 等入口
|
||||
ClientReact->>Browser: 关联交互逻辑与已有 DOM
|
||||
```
|
||||
|
||||
`renderToPipeableStream` 是 Node 流环境的一条 React 服务端输出路径;浏览器的 `hydrateRoot` 接管已有的服务端 HTML 并建立客户端交互。初始渲染结果要符合 hydration 的一致性要求,不能把服务器函数对象、闭包或堆地址当成直接转移到浏览器的状态。[服务端流渲染](https://react.dev/reference/react-dom/server/renderToPipeableStream)、[hydrateRoot](https://react.dev/reference/react-dom/client/hydrateRoot)
|
||||
|
||||
服务端和客户端分别拥有自己的 JS 执行环境与对象。Effects 不在服务端渲染时运行;需要客户端的交互逻辑仍由浏览器加载和执行。SSR、React Server Components、服务器函数与框架路由是不同机制;本节追踪传统 SSR/hydration,不把其他机制默认叠加进去。
|
||||
|
||||
## Node 与 Chromium
|
||||
|
||||
### 请求得到什么与客户端怎么使用分别决定
|
||||
|
||||
服务端先按路由或静态资源配置生成响应,客户端再按请求用途、响应信息和自己的规则使用内容。URL 的后缀不能单独决定代码是在服务器执行还是在浏览器执行。
|
||||
|
||||
| 动作 | 服务端可能怎样生成响应 | 浏览器接收后的典型路径 |
|
||||
| --- | --- | --- |
|
||||
| 导航到页面 URL | 静态 HTML 或程序生成 HTML | 导航及文档解析、样式、布局和呈现 |
|
||||
| 页面引用 `<script src="/app.js">` | 读取文件或程序生成 JS | 脚本机制在满足加载、类型及策略条件后安排执行 |
|
||||
| `fetch("/app.js")` | 也可能是同一份 JS 字节 | 得到 Response,读取为文本不自动执行该文本 |
|
||||
| `fetch("/price")` 并解析 JSON | 服务端处理函数计算再序列化 | 创建本地 JS 数据;用户代码决定怎样更新界面 |
|
||||
|
||||
脚本加载和执行规则由 HTML 宿主机制规定;Fetch 返回响应的 API 本身不包含“自动把响应当脚本执行”。直接打开 JS 或 JSON 资源时,显示或下载还受导航、媒体类型和响应头等规则影响,不能假定所有浏览器都采用相同展示界面。[HTML script 规则](https://html.spec.whatwg.org/multipage/scripting.html#the-script-element)、[Fetch 方法](https://fetch.spec.whatwg.org/#fetch-method)
|
||||
|
||||
服务器即使返回 JSON,浏览器也可以显示文本;具有特定应用含义的按钮、图表等需要客户端程序、HTML 或相应查看器的呈现规则。JSON 的数据结构本身不会自动定义完整应用 UI。
|
||||
|
||||
### 浏览器与 Node 的任务管理
|
||||
|
||||
| 维度 | Chromium 中的页面 | Node 应用 |
|
||||
| --- | --- | --- |
|
||||
| 入口 | 导航、脚本/模块、事件、控制台求值等 | 入口模块、REPL、服务器及其他 API 回调 |
|
||||
| 系统事件 | 用户交互、网络、定时器、页面生命周期等 | 网络、文件、定时器、进程等 |
|
||||
| 调度组织 | HTML 任务来源、任务队列、微任务检查点及渲染机会 | libuv 阶段、Node 回调边界及微任务处理 |
|
||||
| 呈现 | DOM、样式、布局、绘制等浏览器设施 | 默认没有页面 DOM 和浏览器绘制阶段 |
|
||||
| 长期状态 | 文档、DOM、监听关联、JS 环境、框架状态 | 模块、服务器、连接、监听关联、JS 环境 |
|
||||
| 实际执行 JS | V8 | V8 |
|
||||
|
||||
浏览器规范中的正式概念是 task;“宏任务”是常见教学叫法。不能把浏览器描述成唯一全局 FIFO 队列。微任务检查点会处理新加入的微任务,渲染还要符合渲染机会条件。[HTML 事件循环](https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model)
|
||||
|
||||
Node 的 timers、poll、check 等阶段来自宿主机制;`setImmediate` 和 `process.nextTick` 不是 ECMAScript 关键词或 V8 自带的全部循环。`nextTick` 的先后还要考虑调用上下文及模块求值方式,不能承诺它在所有情境绝对先于一切 Promise 工作。[Node 阶段与 nextTick](https://nodejs.org/learn/asynchronous-work/event-loop-timers-and-nexttick)
|
||||
|
||||
V8 提供上下文、代码执行和微任务相关能力,宿主通过嵌入接口配合调度。因此“V8 完全没有任何队列”也不准确;完整 I/O 与应用事件循环仍不能统称为 V8。[V8 嵌入说明](https://v8.dev/docs/embed)、[V8 MicrotaskQueue API](https://v8.github.io/api/head/classv8_1_1MicrotaskQueue.html)
|
||||
|
||||
### 同步调用、事件和 REPL 三种入口
|
||||
|
||||
Node HTTP 服务器把请求函数登记到服务器的 request 事件关系中;收到请求后,宿主和服务器设施进入回调,V8 执行用户 JS。运行到普通 `helper()` 调用时则立即进入该函数,不等待另一个 HTTP 事件。监听器是长期关联,每次调用状态是短期上下文。[Node HTTP request 事件](https://nodejs.org/api/http.html#event-request)
|
||||
|
||||
Node REPL 管理输入流、求值上下文、结果输出及会话关闭等;浏览器控制台在所选页面或 frame 的环境中求值,能接触对应 DOM 等宿主对象。它们可以使用同一引擎的求值能力,但会话、绑定规则、可用 API 和后台活动不同。REPL 等输入时,进程不需要一直忙跑一段用户 JS 循环。[Node REPL](https://nodejs.org/api/repl.html)、[Chrome 控制台执行 JavaScript](https://developer.chrome.com/docs/devtools/console/javascript)
|
||||
|
||||
## 五条路径放在同一张表里
|
||||
|
||||
| 路径 | 触发与入口选择 | 执行的推进者 | 跨执行保留的主要状态 | 普通工作结束 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| C 普通进程 | 启动入口、用户调用 | 原生代码及 OS 线程调度 | 程序数据,调用期间的状态 | 返回或退出 |
|
||||
| FastAPI | 服务器接入、框架路由及依赖 | CPython、选定异步环境或线程池 | app、路由、请求、Task/协程等待状态 | 响应及相应范围清理 |
|
||||
| Spring MVC | Servlet 容器、DispatcherServlet | JVM 与容器执行安排 | bean、映射、请求及方法状态 | 返回响应;容器继续存续 |
|
||||
| Unity | 引擎状态与 PlayerLoop 阶段 | Mono/IL2CPP 路径及引擎 | 场景、组件字段、协程等待记录 | 回调返回、禁用或销毁分别发生 |
|
||||
| React 浏览器 | root 更新、状态变化和事件 | React 组织调用,V8 执行,浏览器呈现 | 组件关系、Hook、更新、Effect、DOM | 计算完成、提交和卸载分别发生 |
|
||||
|
||||
钩子表达触发关系,调度器安排工作,解释器或其他执行机制推进代码;数据结构保存跨这些动作的关系。状态与迁移规则、归属与释放规则则决定哪些动作合法,以及活动何时结束。它们不能只用“有一个循环”替代。
|
||||
|
||||
## 对 Endorphin 执行模型的设计分析
|
||||
|
||||
本节提出研究维度及验证场景,不确认新的语法、原生任务类型或调度 API。现有语言决定仍以 [Preflight 与 inflight](../guide/05-preflight-and-inflight.md)、[函数与调用](../guide/09-functions-and-calls.md)、[Object 与类型系统](../guide/07-top-level-types/README.md)、[资源访问与呈现](../guide/11-resource-access-and-presentation.md)、[REPL 提案](../guide/14-repl.md)和[规范状态](specification-status.md)为准。
|
||||
|
||||
### 先描述可观察的执行契约
|
||||
|
||||
| 维度 | 需要形成的明确契约 | 可用的验证场景 |
|
||||
| --- | --- | --- |
|
||||
| 定义与活动 | 定义准备、对象创建、调用开始分别由什么动作发生 | 查看函数或导入是否触发业务调用 |
|
||||
| 执行入口 | 显式调用、REPL 输入、界面事件和平台触发怎样进入 | 提交参数后何时真正执行定价函数 |
|
||||
| 一次执行的单位 | 本次调用及其子调用、等待和结果如何关联 | 同一函数同时接受两个不同输入 |
|
||||
| 上下文 | 代码与依赖、输入、局部状态、进度、结果接收方保存在哪里 | 等待后继续使用原来的输入 |
|
||||
| 顺序与更新边界 | 哪些工作必须有序,何时发布可观察结果 | 同一事件引起两个更新,界面看到什么 |
|
||||
| 等待与继续 | 保留本次状态、等待条件、恢复入口与失败传播 | 数据未就绪后继续执行,而非重复业务写入 |
|
||||
| 并发与隔离 | 同一对象上的活动如何协调,哪些状态可共享 | 两次执行同时更新同一个运行对象 |
|
||||
| 取消与归属 | 谁能结束活动,子活动和资源如何跟随 | REPL 关闭或 UI 消失后仍在等待的计算 |
|
||||
| 位置与权限 | 平台怎样决定执行位置和有效能力 | 同一函数被不同身份使用,跨端对象如何关联 |
|
||||
| 清理与保存 | 活动结束、资源解除、结果留存和对象回收分别何时发生 | 查看历史结果不重放计算,订阅结束能释放关联 |
|
||||
|
||||
执行记录可以引用平台对象,但数据对象、函数定义、调用状态、结果句柄、触发关联的职责仍需区分。拥有平台 ID 并不自动意味着需要执行;存储局部变量也不自动意味着具备跨进程恢复能力。持久化正在执行的状态还涉及代码版本、外部操作及恢复边界,不能从“状态可保存”直接推出可靠重启。
|
||||
|
||||
### 用一条轨迹检查规则是否完整
|
||||
|
||||
下面是研究用的行为轨迹,不是 Endorphin 源码或新增 API。
|
||||
|
||||
```text
|
||||
定义已准备
|
||||
→ 用户明确提交一组输入
|
||||
→ 建立本次执行及有效上下文
|
||||
→ 获得执行机会并进入函数
|
||||
→ 遇到未就绪操作,保留进度与等待关联
|
||||
→ 条件满足后再次获得执行机会
|
||||
→ 从继续位置推进,交付结果或失败
|
||||
→ 解除本次活动资源;按规则保留结果或关联
|
||||
```
|
||||
|
||||
这条轨迹至少能区分“输入还没准备好”“已经执行但正在等待”“已经完成而结果仍被查看”。如果界面重新呈现结果不应重新运行写入,就需要明确结果查看与调用触发的边界;如果不允许自动重试,就不能以重算替代恢复。
|
||||
|
||||
### 再选择队列与钩子的组织方式
|
||||
|
||||
以下是设计比较,不是已采用方案。
|
||||
|
||||
| 候选组织方式 | 适合表达的要求 | 必须另外处理的边界 |
|
||||
| --- | --- | --- |
|
||||
| 直接同步调用 | 明确调用关系及立即返回 | 长时间运行、等待及并发活动 |
|
||||
| 固定阶段回调 | 稳定周期或固定阶段的工作 | 不活动对象、阶段顺序及启停规则 |
|
||||
| 事件订阅 | 按事件选择处理逻辑 | 订阅所有者、取消、重复事件及积压 |
|
||||
| 可暂停任务与继续关系 | 等待后保留本次计算的进度 | 调度、公平性、失败、取消及资源归属 |
|
||||
| 组件更新与提交边界 | 把计算与可观察界面更新关联 | 可重算性、副作用和结果发布时机 |
|
||||
| 分层队列或检查点 | 区分不同工作的顺序及更新边界 | 饥饿、重入、无限连锁更新及跨队列顺序 |
|
||||
|
||||
宏任务/微任务只是一种组织顺序的具体办法。Endorphin 是否需要类似机制,应由事件处理、继续计算和结果呈现之间的顺序要求决定。固定阶段与依赖驱动的更新也可以服务不同实体,不需要先把所有对象放入一个通用循环。
|
||||
|
||||
远程数据同步可用于检查跨端身份、变化到达和更新顺序;它只是验证场景之一。执行模型的主问题仍是:入口怎样建立活动,执行如何推进,等待怎样保存并继续,以及活动由谁结束。
|
||||
|
||||
[12 门语言的执行模型与生命周期](language-runtime-lifecycles.md) · [关键词手册](language-keywords.md) · [返回目录](../README.md)
|
||||
+17
-3
@@ -12,25 +12,39 @@
|
||||
| r/w/x | 读取、编辑资源与使用程序的操作类别;业务写入不自动要求调用者拥有编辑权 | [操作分工](../guide/02-user-identity.md#26-rwx-的操作分工) |
|
||||
| workspace 角色 | 在 workspace 范围授予常用权限组合与管理能力的成员角色 | [Workspace 角色与授权](../guide/02-user-identity.md#27-workspace-角色与授权) |
|
||||
| 代码可视域 | 声明可在什么程序位置被引用的范围,区别于平台用户权限 | [平台权限与代码可视域](../guide/02-user-identity.md#29-平台权限与代码可视域) |
|
||||
| namespace | 资源归属、组织与检索的单位;代码资源形成可见代码视图 | [namespace](../guide/03-namespaces.md) |
|
||||
| namespace | workspace 内部的命名、组织与检索单位;成员入口指向资源 ID | [namespace](../guide/03-namespaces.md) |
|
||||
| namespace key | workspace handle 与非空 namespace 路径组成的定位标识 | [namespace](../guide/03-namespaces.md) |
|
||||
| 代码段 | 独立存储、具有明确归属的代码内容单位 | [代码存储与视图](code-storage-and-views.md) |
|
||||
| 可见代码视图 | 由索引成员关系获得的 namespace 逻辑代码集合 | [代码存储与视图](code-storage-and-views.md) |
|
||||
| use | 引用完整 namespace key 的声明 | [程序结构与导入](../guide/04-program-structure.md) |
|
||||
| Preflight | 定义准备与检查阶段;定义生命周期覆盖创建、准备、持续可引用、更新与退出 | [Preflight 与 inflight](../guide/05-preflight-and-inflight.md) |
|
||||
| inflight | 实际执行阶段;运行时生命周期覆盖调用、实例、任务及保存的运行状态 | [Preflight 与 inflight](../guide/05-preflight-and-inflight.md) |
|
||||
| REPL | 持续接收输入、检查并求值、呈现结果的交互式会话;Endorphin 的会话及控制行为为设计提案 | [交互式会话(REPL)](../guide/14-repl.md) |
|
||||
| 基础常量资源 | 数值、文本、媒体和 GIS 等不可原地修改的基础内容 | [资源、类型与类](../guide/07-types-and-classes.md#71-类型标注) |
|
||||
| 统一数值 | 不按整数位宽或浮点编码分型的数值类别;本文暂用 Number 命名 | [资源、类型与类](../guide/07-types-and-classes.md#71-类型标注) |
|
||||
| 格式归一化 | 接受的媒体和 GIS 格式导入后转写为内部标准格式,导出时再编码 | [资源、类型与类](../guide/07-types-and-classes.md#71-类型标注) |
|
||||
| 类型 | 描述资源或值的结构及其允许用法的定义 | [资源、类型与类](../guide/07-types-and-classes.md) |
|
||||
| Object | 没有父类型的继承根;自身是 Type 的实例,平台按具体类型管理对象生命周期 | [Object](../guide/07-top-level-types/README.md#object) |
|
||||
| 平台对象 | 由平台识别、管理和存储的对象;描述已有 Object 模型的管理方式,不另设基础类型 | [跨端对象与同步](../guide/11-resource-access-and-presentation.md#117-跨端对象与同步) |
|
||||
| 本地副本 | 执行端为远程对象准备的类型化本地表示,保存已取得的数据及目标身份关联 | [跨端对象与同步](../guide/11-resource-access-and-presentation.md#117-跨端对象与同步) |
|
||||
| 同步关联 | 将对象后续变化通过网络传递到本地副本的持续关系,不保证多端瞬时一致 | [跨端对象与同步](../guide/11-resource-access-and-presentation.md#117-跨端对象与同步) |
|
||||
| Type | 类型对象的实例类型;自身也是 Type 的实例,并继承 Object | [Type](../guide/07-top-level-types/definitions.md#type) |
|
||||
| 实例化线 | 对象与其直接实例类型的关系,以 x ∈ T 表示;类型自身也是对象 | [实例化线](../guide/07-top-level-types/README.md#实例化线) |
|
||||
| 继承线 | 子类型与父类型的关系,以 A ⊆ B 表示,区别于对象的实例类型关系 | [继承线](../guide/07-top-level-types/README.md#继承线) |
|
||||
| atom | 对象可独立识别、保存和引用的资源单元,允许由其他对象组合而成 | [Object、atom 与资源 ID](../guide/07-top-level-types/README.md#objectatom-与资源-id) |
|
||||
| 类型系统 | 在 Object 基础上约束成员、容器、引用和定义,组织高级结构及能力关系的规则体系 | [Object 与类型系统](../guide/07-top-level-types/README.md) |
|
||||
| 顶级类型 | 平台原生支持的对象类型;Object 提供共同基础,其他类型规定具体结构及行为 | [Object 与类型系统](../guide/07-top-level-types/README.md) |
|
||||
| 资源 ID | 独立于 workspace、namespace 命名入口的逻辑资源身份 | [资源引用](../guide/07-top-level-types/references.md) |
|
||||
| trait | 构造可显式实现与组合的能力定义对象的入口,自身也是对象;Trait 为能力定义的类型候选 | [trait、Trait](../guide/07-top-level-types/definitions.md#traittrait) |
|
||||
| Function | 平台原生的可调用代码类型,可扩展函数行为和生命周期;具体语法待定 | [Function](../guide/07-top-level-types/functions.md) |
|
||||
| 类型身份 | 由具体类型声明确定的身份;成员相同不自动使不同声明兼容 | [类型身份与兼容](../guide/07-types-and-classes.md#76-类型身份与兼容) |
|
||||
| class | 组织数据结构、字段和成员函数的声明 | [资源、类型与类](../guide/07-types-and-classes.md) |
|
||||
| class | 构造具有名义身份的类型对象的入口,自身也是对象;构造的类型组织字段与成员函数 | [class](../guide/07-top-level-types/definitions.md#class) |
|
||||
| 表达式 | 描述计算并产生值的源码形式 | [表达式与绑定](../guide/08-expressions-and-bindings.md) |
|
||||
| 绑定 | 将表达式结果关联到局部名称 | [表达式与绑定](../guide/08-expressions-and-bindings.md) |
|
||||
| 变量 | 可改变目标的资源引用;具体声明和赋值形式待定 | [变量与资源引用](../guide/08-expressions-and-bindings.md#86-变量与资源引用) |
|
||||
| 函数 | 定义输入、结果和执行逻辑的可调用声明 | [函数与调用](../guide/09-functions-and-calls.md) |
|
||||
| 数据依赖 | 后续计算需要前一计算结果的关系 | [函数与调用](../guide/09-functions-and-calls.md) |
|
||||
| agent | 复用共有成员并建立模型驱动执行与状态关联的语言资源声明 | [Agent](../guide/13-agents.md) |
|
||||
| Agent、agent | Agent 为运行对象类型;agent 为具体类型对象的构造入口,二者都属于对象体系 | [Agent](../guide/13-agents.md) |
|
||||
| tool | 关联为模型可选能力的函数,可以是外部引用或内部成员函数 | [Tools 与逻辑实现](../guide/13-agents.md#133-tools-与逻辑实现) |
|
||||
| memory | 信息保留与恢复的职责,包含会话记忆、检查点和长期记忆 | [Memory 与保存恢复](../guide/13-agents.md#134-memory-与保存恢复) |
|
||||
| state | 当前业务及执行状态,可用于有限状态机与条件路由 | [State、有限状态机与路由](../guide/13-agents.md#135-state有限状态机与路由) |
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,384 @@
|
||||
# 12 门语言的执行模型与生命周期
|
||||
|
||||
本文比较代码如何进入执行、运行状态如何保存、等待后如何继续,以及资源如何结束存续。逐词含义见[关键词手册](language-keywords.md);请求、场景和界面的完整路径见[框架如何接管代码执行](framework-runtime-lifecycles.md)。本文是外部语言参考,不定义 Endorphin 的新语法或默认调度规则。
|
||||
|
||||
执行模型资料核对日期:2026-10-13。关键词版本基线沿用原手册;这里分析指定实现的机制,不宣称覆盖所有实现或版本。Python 使用 CPython 3.14;Java 使用 Java SE 26 的规范;C 使用 C23 公开草案;C++ 使用公开工作草案的相关条款,不将其所有新增能力归入 C++23。Go runtime、React 源码和其他持续更新的官方资料,只作为所注明实现的证据。Kotlin 已发布规范中的协程说明用于解释机制,不作为 Kotlin 2.4 全量版本审计;Julia 使用官方 v1 文档,不将实现细节冻结为 1.11 的全部承诺。
|
||||
|
||||
## 阅读路径
|
||||
|
||||
先阅读统一模板,再选一门熟悉的语言。建立普通调用的认识后,比较协程和任务,最后进入框架案例。
|
||||
|
||||
| 语言 | 分析入口 | 框架或宿主案例 |
|
||||
| --- | --- | --- |
|
||||
| Python | [CPython、执行帧与协程](#1-python) | [FastAPI](framework-runtime-lifecycles.md#路径二fastapi) |
|
||||
| JavaScript | [执行上下文、Promise 与宿主](#2-javascript) | [Node/Chromium](framework-runtime-lifecycles.md#node-与-chromium)、[React](framework-runtime-lifecycles.md#路径五react) |
|
||||
| TypeScript | [类型处理与 JavaScript 执行](#3-typescript) | [TSX 与 React](framework-runtime-lifecycles.md#路径五react) |
|
||||
| Java | [JVM、类初始化与线程](#4-java) | [Spring Boot](framework-runtime-lifecycles.md#路径三spring-boot) |
|
||||
| C | [进程入口与存储期](#5-c) | [普通进程](framework-runtime-lifecycles.md#路径一c-普通进程) |
|
||||
| C++ | [对象生命周期与协程帧](#6-c) | 库或宿主提供调度 |
|
||||
| C# | [.NET、Task 与状态机](#7-c) | [Unity](framework-runtime-lifecycles.md#路径四unity) |
|
||||
| Go | [goroutine、channel 与 runtime](#8-go) | runtime 调度 |
|
||||
| Rust | [所有权、Future 与 executor](#9-rust) | 异步运行库提供调度 |
|
||||
| Swift | [ARC、Task 与 executor](#10-swift) | 并发运行时及应用宿主 |
|
||||
| Kotlin | [Continuation、Job 与 dispatcher](#11-kotlin) | 协程库及目标平台 |
|
||||
| Julia | [方法、Task 与调度](#12-julia) | Julia 运行时 |
|
||||
|
||||
## 统一分析模板
|
||||
|
||||
### 常用结构名称
|
||||
|
||||
| 名称 | 本文中的含义 |
|
||||
| --- | --- |
|
||||
| frame/执行帧 | 一次调用或执行的参数、局部状态与继续关系;具体布局由实现决定 |
|
||||
| continuation/继续关系 | 暂停后该怎样继续计算,可以用保存状态、函数或其他结构表达 |
|
||||
| 状态机 | 将执行进度表示为不同状态及迁移,并保存跨暂停需要的数据 |
|
||||
| scheduler/executor | 接收工作并安排推进的设施;不等于所有计算都由它解释执行 |
|
||||
| awaiter/等待协议 | 检查是否完成,并在需要等待时建立继续关系的机制 |
|
||||
| Task/Job | 具体运行环境管理的活动或工作;同名设施在不同语言中并不等价 |
|
||||
| Future/Promise | 表达结果及其后续取得或推进协议的设施;不等于专属线程 |
|
||||
| GC/ARC/RAII | 分别强调可达性回收、引用计数管理、将资源管理关联到对象初始化与析构;具体保证见各语言 |
|
||||
| JIT/AOT | 分别表示运行时编译与提前编译;它们回答代码怎样准备,不直接定义哪个业务事件触发调用 |
|
||||
|
||||
### 生命周期属于一个具体实体
|
||||
|
||||
“程序的生命周期”通常包含多个不同尺度的生命周期。进程仍然存在时,函数调用可以已经返回;组件仍然存在时,某次渲染可以已经完成;任务暂停时,其上下文仍然存在。分析时先明确实体,再讨论状态。
|
||||
|
||||
| 实体 | 典型开始 | 典型结束 | 不能混淆的关系 |
|
||||
| --- | --- | --- | --- |
|
||||
| 进程或应用 | 启动入口被接管 | 正常退出、关闭或终止 | 应用存续不意味着用户代码持续执行 |
|
||||
| REPL 会话 | 创建输入与求值上下文 | 会话关闭 | 一次输入完成后,绑定仍可保留 |
|
||||
| 函数定义 | 定义被创建、加载或准备 | 不再需要或所属环境结束 | 定义存在不意味着函数体已经执行 |
|
||||
| 一次调用 | 控制流进入函数 | 返回或异常离开 | 同一函数可以对应很多次独立调用 |
|
||||
| 协程或任务 | 创建状态及进入执行 | 完成、失败或取消处理结束 | 创建、调度、首次运行可能是不同动作 |
|
||||
| 组件或订阅 | 挂载、启用或注册 | 卸载、禁用或取消订阅 | 一次回调返回通常不销毁组件或订阅 |
|
||||
| 数据对象或资源 | 构造、分配或获得资源 | 释放、销毁或回收 | 内存回收与文件、连接关闭分别处理 |
|
||||
|
||||
### 定义、上下文、管理结构分别保存信息
|
||||
|
||||
下面是比较用的概念分类,不要求每个实现都存在三个同名结构。
|
||||
|
||||
| 结构组 | 保存的信息 | 常见实例 |
|
||||
| --- | --- | --- |
|
||||
| 代码与定义 | 可执行逻辑、类型、模块、依赖及捕获环境 | code object、函数对象、方法元数据、机器码、模块记录 |
|
||||
| 一次执行的上下文 | 输入、局部绑定、进度、等待及结果关系 | 栈帧、协程帧、Continuation、goroutine 栈 |
|
||||
| 调度与管理结构 | 就绪工作、等待者、触发关联及所有者 | 就绪队列、I/O 注册表、Task、Job、组件树、订阅表 |
|
||||
|
||||
执行上下文需要能够支持下列职责,但信息可以分散保存、被编译器消除,或由外部宿主提供。
|
||||
|
||||
| 信息 | 作用 | 典型承载方式 |
|
||||
| --- | --- | --- |
|
||||
| 本次采用的代码与依赖 | 确定执行哪份逻辑 | 方法元数据、函数引用、代码地址与环境 |
|
||||
| 输入与局部绑定 | 保存这次计算的数据 | 局部槽位、寄存器、栈、状态机字段 |
|
||||
| 当前进度 | 决定继续执行的位置 | 指令位置、返回地址、状态机标签 |
|
||||
| 执行状态 | 区分运行、等待和结束 | Task/Job 状态、调度器记录 |
|
||||
| 等待条件与继续位置 | 外部条件满足后能够继续 | awaiter、Waker、等待队列、Continuation |
|
||||
| 调用关系与结果接收者 | 交付返回值或失败 | 调用栈、Promise reaction、父任务、回调 |
|
||||
| 执行身份与可用能力 | 判断操作的归属与授权 | 进程权限、请求上下文、宿主能力;不是所有语言执行帧的原生字段 |
|
||||
|
||||
对象地址只在所在进程的地址空间里有意义。网络发送的是协议表示;接收端创建或更新自己的对象。跨端关联必须另有身份和通信约定,不能从局部变量名字推断远端内存位置。Endorphin 对平台对象的说明见[资源访问与呈现](../guide/11-resource-access-and-presentation.md#117-跨端对象与同步)。
|
||||
|
||||
### 触发、调度与执行承担不同职责
|
||||
|
||||
触发关系确定发生某个条件后应进入哪段逻辑。调度确定工作何时获得执行机会。执行引擎或原生代码推进具体计算。普通同步调用可以直接进入函数,不经过应用任务队列;应用事件循环之外,还可能有操作系统线程调度。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[启动、输入、事件或条件满足] --> B[确定入口与输入]
|
||||
B --> C[直接调用或提交可运行工作]
|
||||
C --> D[执行引擎或原生代码推进]
|
||||
D --> E{本次执行的结果}
|
||||
E --> F[返回或失败:交付结果并清理]
|
||||
E --> G[等待:保存上下文与等待关系]
|
||||
G --> H[条件满足:重新获得执行机会]
|
||||
H --> D
|
||||
```
|
||||
|
||||
图中是概念路径,不能据此推出统一队列、抢占策略或状态枚举。回调注册通常保存关联,注册函数自身也可能执行初始化逻辑;必须查具体 API。等待结果的任务也不一定需要不断主动轮询。
|
||||
|
||||
比较可暂停活动时,可以使用下面的分析状态;它们不是各语言共有的原生枚举。
|
||||
|
||||
| 分析状态 | 进入条件 | 后续处理 |
|
||||
| --- | --- | --- |
|
||||
| 已创建 | 逻辑与初始上下文已经关联 | 可能尚未调度或运行,例如新建的 Julia Task |
|
||||
| 可运行 | 有条件推进,但尚未获得执行机会 | 由相应调度策略选中 |
|
||||
| 运行中 | 正在推进代码 | 继续、等待、完成或失败 |
|
||||
| 等待中 | 当前不能继续,已保存状态及等待关系 | 条件满足后获得继续机会 |
|
||||
| 已完成/失败 | 逻辑得到结果或以错误结束 | 交付结果,完成相应清理;结果句柄仍可存续 |
|
||||
|
||||
取消请求可以在运行或等待期间出现;活动接受取消、执行清理并终止之前,不能把“请求取消”直接当成“已结束”。组件的启用、提交或卸载也不是上表的同一套状态。
|
||||
|
||||
### 恢复、重算、释放各有含义
|
||||
|
||||
恢复是在保留的上下文中继续;重算是开始另一次求值。React 再次调用组件属于重新计算,Rust executor 再次 poll 同一个 Future 属于推进保存的状态。取消通常是请求停止及处理清理,不自动撤销已经发生的写入。GC 判断内存对象是否可回收,不代替所有业务资源的关闭。
|
||||
|
||||
## 1. Python
|
||||
|
||||
**入口与执行者。** CPython 执行脚本、模块或 REPL 输入中的代码块。模块顶层会执行;执行 `def` 创建函数并处理默认值、装饰器等,普通函数体在调用时运行。`class` 的类体在定义类时执行。首次导入通常执行模块初始化,后续导入通常使用模块缓存。Python 规范中的执行帧概念与 CPython 具体实现应分开。[Python 执行模型](https://docs.python.org/3.14/reference/executionmodel.html)、[复合语句](https://docs.python.org/3.14/reference/compound_stmts.html)
|
||||
|
||||
| 结构 | 保存什么 | 生命周期及归属 |
|
||||
| --- | --- | --- |
|
||||
| code object | 编译后的代码及常量、名称等元数据 | 可被函数引用和多次执行;不包含某次调用的全部数据 |
|
||||
| function object | code、全局环境、默认值、闭包等 | 定义执行时创建,通常跨多次调用存续 |
|
||||
| 执行帧及解释器内部状态 | 局部绑定、进度、调用关系 | 一次执行;可因生成器、协程或外部引用保留 |
|
||||
| coroutine/generator、asyncio Task | 可暂停状态;Task 进一步跟踪结果、取消和调度 | 调用者或事件循环持有,完成不等于引用立即消失 |
|
||||
| PyObject 及具体对象结构 | CPython 对象的类型及具体内容 | 对象存续期间;不是“当前正在执行”的标记 |
|
||||
|
||||
`PyObject` 是 CPython 对象表示的基础,不是在每次运行字节码时才统一创建。启动初始化、执行定义、构造值都可能产生对象;code、function 与一次执行的帧也不同。[对象 C API 说明](https://docs.python.org/3.14/c-api/intro.html#objects-types-and-reference-counts)、[函数对象 C API](https://docs.python.org/3.14/c-api/function.html)、[代码对象 C API](https://docs.python.org/3.14/c-api/code.html)
|
||||
|
||||
具体帧内部表示不等于每次调用立即创建一个可见 `PyFrameObject`。CPython 的帧优化允许在需要时才物化相应 Python 帧对象;不能用调试器看见的对象反推每次调用的全部分配行为。[按需创建 Python 帧](https://docs.python.org/3.14/whatsnew/3.11.html#cheaper-lazy-python-frames)
|
||||
|
||||
**进入与等待。** 普通函数调用立即进入函数体;生成器调用先取得生成器,迭代推进它。调用 `async def` 先得到 coroutine,随后由 `await`、`asyncio.run` 或 Task 等方式驱动。Task 的急切执行配置会改变首次推进时机,不能一律理解为下一轮循环才开始。[asyncio 协程与任务](https://docs.python.org/3.14/library/asyncio-task.html)
|
||||
|
||||
下面是 CPython/asyncio 的独立示例,预期输出顺序为 `created`、`body`、`42`,不是运行日志。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
|
||||
async def price():
|
||||
print("body")
|
||||
await asyncio.sleep(0)
|
||||
return 42
|
||||
|
||||
async def main():
|
||||
pending = price()
|
||||
print("created")
|
||||
print(await pending)
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
**结束与关键词。** `return` 和异常结束调用;`yield` 保存生成器继续状态,`await` 表达等待。`with`、`finally` 用于资源退出处理;`del` 删除绑定等,不保证对象立即销毁。CPython 的引用计数及循环 GC 是实现机制,不是所有 Python 实现必须照搬的机制。[Python 数据模型](https://docs.python.org/3.14/reference/datamodel.html)。请求入口另由 [FastAPI 与 ASGI](framework-runtime-lifecycles.md#路径二fastapi)组织。
|
||||
|
||||
## 2. JavaScript
|
||||
|
||||
**入口与执行者。** 宿主启动脚本或模块求值,再通过普通调用和回调进入函数。V8 是 Node 与 Chromium 使用的执行引擎;网络、DOM、定时器和完整宿主事件循环分别由宿主提供。ECMAScript 定义执行上下文与环境记录,它们是规范模型,不要求 V8 使用相同名称或布局。[ECMAScript 执行上下文](https://tc39.es/ecma262/2026/multipage/executable-code-and-execution-contexts.html)
|
||||
|
||||
| 结构 | 保存什么 | 生命周期及归属 |
|
||||
| --- | --- | --- |
|
||||
| 函数、脚本/模块及环境 | 逻辑、绑定和闭包捕获 | 引擎管理;模块求值与函数调用分别发生 |
|
||||
| 执行上下文栈 | 当前函数、环境及执行进度 | 活跃的同步调用;闭包环境可继续存续 |
|
||||
| Promise 与 reaction | 完成状态、结果及后续处理 | Promise 解决后仍可被引用,不等于线程或整个执行帧 |
|
||||
| 生成器/异步继续状态 | 暂停后的局部信息与继续关系 | 引擎保存并按相应协议恢复 |
|
||||
| 宿主任务与微任务管理 | 可运行的回调或 job | 队列、检查点和执行时机受宿主规范约束 |
|
||||
|
||||
**进入与等待。** 普通函数立即运行;`async` 函数调用会运行同步前缀,再返回 Promise,`await` 后续通过异步继续机制推进;生成器由 `next()` 等驱动。Promise 构造器的 executor 与 `.then()` 注册的后续处理不是同一个时机。[ECMAScript 函数定义](https://tc39.es/ecma262/2026/multipage/ecmascript-language-functions-and-classes.html)、[Promise 对象](https://tc39.es/ecma262/2026/multipage/control-abstraction-objects.html#sec-promise-objects)
|
||||
|
||||
下面是普通脚本示例,预期输出 `start`、`outside`、`resume`。
|
||||
|
||||
```javascript
|
||||
async function price() {
|
||||
console.log("start");
|
||||
await Promise.resolve();
|
||||
console.log("resume");
|
||||
}
|
||||
price();
|
||||
console.log("outside");
|
||||
```
|
||||
|
||||
**调度与结束。** 浏览器在规定位置执行微任务检查点,清空过程中还可加入新微任务;渲染发生在符合条件的渲染机会,不保证每个任务后立即绘制。Node 另有 libuv 阶段和 `process.nextTick` 规则。`return`、`throw`、`try/finally` 描述调用及清理,GC 不能代替解除事件监听或业务资源关闭。[HTML 事件循环](https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model)、[Node 事件循环](https://nodejs.org/learn/asynchronous-work/event-loop-timers-and-nexttick)
|
||||
|
||||
## 3. TypeScript
|
||||
|
||||
**入口与执行者。** 通常由工具处理 TypeScript,输出或交给后续工具产生 JavaScript,再由所选宿主执行。类型检查不是持续坐在 JavaScript 和 V8 之间的另一台解释器。`type`、`interface` 等类型信息通常被擦除;部分构造如普通 `enum`、`namespace` 可以生成运行时代码,不能把所有 TS 内容都理解为无运行效果。[类型擦除](https://www.typescriptlang.org/docs/handbook/2/basic-types.html#erased-types)、[枚举](https://www.typescriptlang.org/docs/handbook/enums.html)、[namespace](https://www.typescriptlang.org/docs/handbook/namespaces.html)
|
||||
|
||||
| 结构 | 保存什么 | 生命周期及归属 |
|
||||
| --- | --- | --- |
|
||||
| 编译工具的 AST、符号与类型信息 | 源码关系、类型检查及转换所需信息 | 构建或编辑会话;通常不进入应用运行堆 |
|
||||
| 生成的 JS 模块、函数和对象 | 真正运行的逻辑与数据 | 采用 JavaScript 的运行模型 |
|
||||
| source map | 源码与生成代码位置的对应 | 调试工具使用;不负责调度 |
|
||||
| 框架自己的组件、任务或请求记录 | React、服务端等管理状态 | 由对应框架承担,不是 TypeScript 类型对象 |
|
||||
|
||||
**调用与等待。** `async`、`await` 的可观察调用行为依照目标 JavaScript 及工具生成的支持代码。TS 的返回类型 `Promise<number>` 描述结果契约,不因类型标注自行启动任务。值导入可能带来模块初始化;纯类型导入不为类型本身创建业务运行对象。
|
||||
|
||||
**TSX 与结束。** JSX 可以由 TypeScript 转换,也可以保留给其他工具处理;生成代码调用 React 等库,然后才进入组件管理。清理、事件循环和对象回收归实际宿主与库。完整路径见 [React 构建、浏览器执行及 SSR](framework-runtime-lifecycles.md#路径五react)。[TypeScript JSX 模式](https://www.typescriptlang.org/docs/handbook/jsx.html)
|
||||
|
||||
## 4. Java
|
||||
|
||||
**入口与执行者。** 启动器选择入口,JVM 完成必要的类加载、链接、初始化并调用入口方法。示例可采用传统 `static main(String[])`,但不能把 Java SE 26 的所有入口都限定为这个签名。类初始化与实例构造也不同;`import` 是名称使用规则,不是每次运行到一行就远程加载并执行一个类。[Java 启动与初始化](https://docs.oracle.com/javase/specs/jls/se26/html/jls-12.html)
|
||||
|
||||
| 结构 | 保存什么 | 生命周期及归属 |
|
||||
| --- | --- | --- |
|
||||
| 类元数据、方法及运行时常量池 | 已加载定义与方法逻辑 | JVM/类加载器管理 |
|
||||
| 每线程的 JVM 栈与 frame | 局部变量、操作数栈及调用关联 | 一次方法调用建立 frame,正常或异常离开时结束 |
|
||||
| 堆中的实例 | 字段与对象关系 | 可越过调用边界,由 GC 管理可达性 |
|
||||
| Thread、执行器及 Future 类设施 | 线程活动、待提交工作和结果 | 标准库及宿主策略;不要求统一事件循环 |
|
||||
|
||||
JVM 规范区分共享堆与每线程状态,但不规定所有实现的 GC、JIT 或物理内存布局。解释执行、编译后的机器码执行都可实现相同方法语义。[JVM 运行时数据区与 frame](https://docs.oracle.com/javase/specs/jvms/se26/html/jvms-2.html)
|
||||
|
||||
**开始与等待。** 普通方法调用直接进入;`Thread.start()` 启动线程执行其逻辑,而直接调用 `run()` 仍是普通方法调用。平台线程、虚拟线程、执行器及异步结果设施各有管理契约。阻塞当前线程不是“Java 必须有一个浏览器式微任务队列”。[Thread API](https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/lang/Thread.html)
|
||||
|
||||
**结束与关键词。** `return`、`throw` 结束调用,`finally` 和带资源的 `try` 处理退出;对象可达性与外部资源关闭分别判断。`synchronized` 影响互斥和内存可见性,不负责启动应用请求。Spring 中的 bean 和请求生命周期见 [Spring Boot 案例](framework-runtime-lifecycles.md#路径三spring-boot)。
|
||||
|
||||
## 5. C
|
||||
|
||||
**入口与执行者。** 在 hosted 环境中,启动流程完成必要准备后进入 `main`;freestanding 环境的启动由实现规定。常见原生实现将函数编译为机器码,由操作系统启动进程、调度线程,CPU 执行指令。C 规范不要求应用事件循环,也不规定一定有某种物理栈布局。[C23 公开草案 N3096,5.1.2、6.2.4](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf)
|
||||
|
||||
| 结构 | 保存什么 | 生命周期及归属 |
|
||||
| --- | --- | --- |
|
||||
| 可执行代码、全局及静态对象 | 函数逻辑和长期状态 | 加载与启动流程;静态存储期贯穿程序执行 |
|
||||
| ABI 约定下的寄存器与栈等 | 参数、局部状态和返回位置 | 常见实现的一次调用;内联可消除独立栈帧 |
|
||||
| 分配存储区及指针 | 动态数据与访问地址 | `malloc`/`free` 等接口管理;C 不提供默认 GC |
|
||||
| 库自建的回调表、队列或线程记录 | 外部事件与执行关联 | 由库或宿主定义,不能从 C 关键词推出 |
|
||||
|
||||
**调用与等待。** 执行调用表达式进入函数,再返回调用位置。保存函数指针不会自动运行函数。同步 I/O 可能阻塞线程;非阻塞 I/O 与事件循环需要操作系统和库的接口。`while` 可以写调度循环,也可以只是计算循环,两者用途不同。
|
||||
|
||||
**结束与关键词。** 自动存储期、静态存储期和分配存储期不同;离开函数不自动释放所有动态内存。`static`、`_Thread_local` 等影响存储属性,`return` 结束函数;`free`、`atexit` 是库名称。正常退出和强制终止的清理保证不同。完整入口例子见[普通进程路径](framework-runtime-lifecycles.md#路径一c-普通进程)。
|
||||
|
||||
## 6. C++
|
||||
|
||||
**入口与执行者。** 普通原生程序经启动及初始化进入 `main`,函数通过调用表达式执行。与 C 相比,C++ 特别区分存储的取得、对象生命周期开始、析构和存储释放;这些步骤不能只合称“对象在内存里”。[启动](https://eel.is/c++draft/basic.start)、[对象生命周期](https://eel.is/c++draft/basic.life)
|
||||
|
||||
| 结构 | 保存什么 | 生命周期及归属 |
|
||||
| --- | --- | --- |
|
||||
| 编译后的函数与类型相关信息 | 调用逻辑、布局及所需分派信息 | 编译实现管理,不要求所有类型都有运行时对象 |
|
||||
| 普通调用状态与自动对象 | 参数、局部数据和退出时析构关系 | 正常离开及适用的异常展开触发析构 |
|
||||
| 所有权容器与动态对象 | 指针及释放责任 | 如 RAII 包装器;原始指针本身不自动表达所有权 |
|
||||
| coroutine state、promise 与 awaiter | 参数、跨暂停局部状态及继续协议 | 编译器与库共同管理,最终需要适当销毁协程状态 |
|
||||
|
||||
**进入与等待。** `co_await`、`co_yield`、`co_return` 参与协程协议。首次是否暂停由 promise 的 `initial_suspend` 等决定;等待是否真暂停由 awaiter 决定。C++ 不因为出现 `co_await` 就自带统一 scheduler 或创建线程。这里的 promise 是协程协议对象,不能直接等同于 JavaScript Promise。[协程定义](https://eel.is/c++draft/dcl.fct.def.coroutine)
|
||||
|
||||
**结束与关键词。** RAII 把资源退出关联到对象析构,`try/throw` 的异常展开可触发清理;异常终止等情形不能套用普通展开保证。协程逻辑完成后还可能停在最终暂停点,完成和 frame 释放不同;裸 handle 的遗失不自动等于安全销毁。`delete`、析构及所有权包装器负责相应存续,`constexpr` 等编译期能力不属于宿主事件调度。[析构函数](https://eel.is/c++draft/class.dtor)
|
||||
|
||||
典型协程轨迹:调用建立状态 → 按 initial_suspend 协议继续或暂停 → awaiter 检查与继续 → 逻辑完成 → 最终暂停及状态销毁按各自协议处理。scheduler 是库或宿主角色,不由协程关键词单独决定。
|
||||
|
||||
## 7. C#
|
||||
|
||||
**入口与执行者。** 以常见 .NET 应用为基线,编译产生程序集中的 CIL 和元数据,运行时通过 JIT 等路径执行;AOT 是另一种路径。入口可由 `Main` 或顶层语句等构成。CLR 管理执行与内存,不自动为所有应用规定 Unity 的帧循环。[托管执行过程](https://learn.microsoft.com/en-us/dotnet/standard/managed-execution-process)
|
||||
|
||||
| 结构 | 保存什么 | 生命周期及归属 |
|
||||
| --- | --- | --- |
|
||||
| 程序集、类型和方法元数据 | 可执行定义及类型关系 | 加载及运行环境管理 |
|
||||
| 普通方法调用状态 | 参数、局部状态和返回关系 | 调用进入至返回或异常离开 |
|
||||
| 编译器生成的 async 状态机 | 跨暂停局部状态、当前位置和 awaiter | 一次异步调用;具体表示可优化 |
|
||||
| Task 与继续处理 | 完成状态、结果、异常等 | 可被多方等待;不等于一个专属线程 |
|
||||
| SynchronizationContext/TaskScheduler 等 | 继续工作的执行策略 | 库、宿主和调用配置共同决定 |
|
||||
|
||||
**开始与等待。** 普通 `async Task` 方法被调用时会先同步推进;遇到尚未完成的 awaitable 才需要暂停。awaitable 已完成时可以继续同步推进,不能照抄 JavaScript `await` 的时间模型。继续位置保存在状态机中,恢复线程由捕获的上下文等规则影响,不保证总在原线程。[Task 异步模型](https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/task-asynchronous-programming-model)
|
||||
|
||||
**结束与关键词。** `return` 或异常使 Task 得到相应结果;取消是合作处理,不是自动回滚。`using`/`await using` 关联资源释放,`lock` 关联互斥,GC 管理内存可达性。Task 完成、资源 Dispose、对象回收是不同事件。[GC 基础](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals)
|
||||
|
||||
Unity 是另一种宿主组合,具有 Mono/IL2CPP 后端及 PlayerLoop;其 `IEnumerator` 协程由引擎推进,不等于 C# async Task。[Unity 案例](framework-runtime-lifecycles.md#路径四unity)
|
||||
|
||||
## 8. Go
|
||||
|
||||
**入口与执行者。** 包变量初始化、`init` 函数及 `main.main` 有规定的启动关系。普通函数调用由当前 goroutine 执行;`go f(args)` 先在调用方求值函数及参数,再让新 goroutine 执行调用。Go 自带 runtime 管理 goroutine,不需要每个应用先自己编写事件循环。[Go 程序初始化与执行](https://go.dev/ref/spec#Program_initialization_and_execution)
|
||||
|
||||
| 结构 | 保存什么 | 生命周期及归属 |
|
||||
| --- | --- | --- |
|
||||
| 包、编译代码与初始化状态 | 定义、全局数据及启动顺序 | 程序初始化和运行 |
|
||||
| goroutine 的栈及 g 记录 | 调用链、保存的执行状态及调度状态 | runtime 管理一次 goroutine 活动 |
|
||||
| M 与 P | OS 线程、执行 Go 代码所需的运行时资源 | 当前 runtime 的 G/M/P 实现模型 |
|
||||
| channel 与等待关系 | 缓冲、通信状态和发送/接收等待者 | 程序引用与 runtime 共同维持 |
|
||||
| 堆对象 | 跨调用、跨 goroutine 的数据 | GC 跟踪可达性;不保证每个局部值都进堆 |
|
||||
|
||||
G/M/P 是具体 Go runtime 的实现说明;P 是调度资源,和用户权限没有关系。goroutine 不要求绑定一个永远专属的 OS 线程。[Go runtime HACKING](https://go.dev/src/runtime/HACKING)、[Go GC 指南](https://go.dev/doc/gc-guide)
|
||||
|
||||
**等待、结束与关键词。** channel 操作、`select` 等可让 goroutine 等待,runtime 保存状态并在条件合适时安排继续。`defer` 在外围函数退出时处理延后工作,不在每次等待时触发。`main` 返回会结束程序,不等待所有其他 goroutine 自行完成;应用需要明确等待和关闭安排。关闭 channel 表达通信协议,不等于强制杀死全部相关 goroutine。
|
||||
|
||||
典型轨迹:包初始化 → main → `go` 启动活动 → runtime 安排推进 → channel 条件不满足时等待 → 条件满足后继续 → 函数退出并执行 defer。main 是否仍在等待其他工作,由应用的同步逻辑决定。
|
||||
|
||||
## 9. Rust
|
||||
|
||||
**入口与执行者。** 普通原生程序从入口进入函数调用。所有权、借用与生命周期注解约束值的使用;生命周期注解通常是编译期关系,不是运行时事件回调。默认内存管理依赖所有权及 Drop,不要求跟踪式 GC。[所有权](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html)
|
||||
|
||||
| 结构 | 保存什么 | 生命周期及归属 |
|
||||
| --- | --- | --- |
|
||||
| 编译后的函数与类型表示 | 调用逻辑和数据布局 | 编译器及链接环境管理 |
|
||||
| 普通调用状态与所有权值 | 参数、局部值及退出释放责任 | 作用域及移动后的所有者决定存续 |
|
||||
| async 生成的 Future 状态 | 跨等待局部数据和进度 | Future 的所有者持有;由 poll 推进 |
|
||||
| Context/Waker | 通知 executor 某项工作应再获推进机会 | Future 与 executor 的恢复协议 |
|
||||
| executor 的 task 与队列 | Future、调度状态及唤醒关联 | 所选异步运行库定义;标准语言不指定唯一 executor |
|
||||
|
||||
**进入与等待。** 调用 `async fn` 创建 Future,函数体在 Future 被推进时执行。`.await` 不自动创建独立并发任务;spawn 由运行库提供。`poll` 返回 `Pending` 或 `Ready`;Waker 通知需要再安排推进,不保证被唤醒就已经有最终结果,也不要求无限忙等。某些 Future 是已启动活动的结果句柄,不能从“Future 惰性推进”推断背后所有工作都尚未开始。[async 函数](https://doc.rust-lang.org/reference/items/functions.html#async-functions)、[Future 协议](https://doc.rust-lang.org/std/future/trait.Future.html)
|
||||
|
||||
**结束与关键词。** 正常作用域退出释放相应拥有的值;panic 的 unwind 与 abort 对析构的保证不同。丢弃 Future 通常停止进一步推进并释放它拥有的状态,但不能撤销已发出的远端操作。`move` 改变捕获方式,`async/await` 参与状态保存与推进,`loop` 本身不构成完整 executor。
|
||||
|
||||
典型轨迹:创建 Future → poll → Pending 时保存等待关系 → Waker 通知再调度 → 再次 poll 推进保存的状态 → Ready 交付结果。Future 结束后的内存与资源释放,还取决于所有者。
|
||||
|
||||
## 10. Swift
|
||||
|
||||
**入口与执行者。** 普通调用与应用入口由 Swift 编译代码及宿主启动;UI 应用还要服从应用框架。调用 async 函数不等于必然创建新的独立 Task。`await` 标记潜在暂停点,不保证每次遇到它都实际暂停。[Swift 官方语言书:并发](https://raw.githubusercontent.com/swiftlang/swift-book/main/TSPL.docc/LanguageGuide/Concurrency.md)
|
||||
|
||||
| 结构 | 保存什么 | 生命周期及归属 |
|
||||
| --- | --- | --- |
|
||||
| 编译代码与类型信息 | 函数逻辑和类型关系 | 编译工具及运行环境管理 |
|
||||
| 普通调用及 async 继续状态 | 参数、局部状态和暂停后进度 | 当前调用与任务活动期间 |
|
||||
| Task、任务组和取消状态 | 并发活动、结果及父子管理关系 | 结构化并发作用域或非结构化任务安排 |
|
||||
| actor/executor 管理 | 隔离及工作执行约束 | 并发运行时;actor 不等于专属线程 |
|
||||
| ARC 管理的类实例 | 强、弱、无主引用及实例数据 | 引用关系决定存续;需要处理强引用环 |
|
||||
|
||||
**调度与恢复。** `async let`、任务组和 `Task` 等表达不同任务组织方式。潜在暂停允许其他工作推进,恢复后不能一般性假定 OS 线程不变。actor 保证相应隔离边界,跨 `await` 仍要考虑其他工作可能改变状态。executor 接收并安排可运行的 job,任务可以跨多个这样的执行片段存续。[Swift SE-0304 的 task、job 与 executor 模型](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0304-structured-concurrency.md#executors)
|
||||
|
||||
**结束与关键词。** 结构化子任务受外围作用域约束;取消是合作机制。`defer` 关联作用域退出,`deinit` 关联类实例销毁,`weak`/`unowned` 影响引用关系。ARC 主要解释类实例的内存管理,不应套用为所有值都对应独立引用计数堆对象。[Swift 官方语言书:ARC](https://raw.githubusercontent.com/swiftlang/swift-book/main/TSPL.docc/LanguageGuide/AutomaticReferenceCounting.md)
|
||||
|
||||
典型轨迹:建立任务作用域 → 调用 async 函数 → 潜在暂停点实际需要等待 → 保存继续状态 → 获得 executor 的继续机会 → 返回结果及完成作用域清理。任务存续跨越暂停,不是每次恢复都创建一份全新业务计算。
|
||||
|
||||
## 11. Kotlin
|
||||
|
||||
**入口与执行者。** 本节以 Kotlin/JVM 为基线:编译结果由 JVM 执行,普通函数有 JVM 调用状态。Kotlin/JS 和 Kotlin/Native 使用不同目标环境,不能把 JVM 栈和 GC 推广到所有 Kotlin 程序。`suspend` 表明函数可以参与可暂停调用,不自行创建一个新协程。[Kotlin 协程规范](https://kotlinlang.org/spec/asynchronous-programming-with-coroutines.html)
|
||||
|
||||
| 结构 | 保存什么 | 生命周期及归属 |
|
||||
| --- | --- | --- |
|
||||
| JVM 方法与类元数据 | 编译后的逻辑及定义 | JVM 目标环境管理 |
|
||||
| Continuation 与状态机 | 结果接收位置、跨暂停局部状态和进度标签 | 可暂停计算的继续关系;不是当前 OS 线程的别名 |
|
||||
| CoroutineContext | dispatcher、Job 等上下文元素 | 协程库及继承、覆盖规则管理 |
|
||||
| Job/Deferred | 活动状态、父子关系、取消及结果 | kotlinx.coroutines 的管理对象,不是语言关键词 |
|
||||
| dispatcher 与等待管理 | 决定工作在哪种执行环境推进 | 所选库和宿主提供 |
|
||||
|
||||
**进入与等待。** `launch`、`async` 等 builder 由 kotlinx.coroutines 创建并组织活动;开始时机受启动模式影响。调用 suspend 函数可继续在现有协程中执行,不等于 spawn。编译器可将暂停路径转换为带局部字段及状态标签的继续结构;恢复可能更换线程,也可能依据 dispatcher 保持特定线程约束。[协程上下文与 dispatcher](https://kotlinlang.org/docs/coroutine-context-and-dispatchers.html)
|
||||
|
||||
**结束与关键词。** Job 完成、子任务结束、取消传播及 `finally` 清理分别遵循协程库与语言规则。JVM 的 GC 管理内存,业务资源仍需合适的关闭协议。`fun`、`suspend`、`try/finally` 分别涉及定义、暂停能力和退出;`Job`、`launch`、`async` 在这里是库设施。
|
||||
|
||||
典型轨迹:builder 组织活动及上下文 → 按启动模式进入 → suspend 调用实际暂停时保存状态 → 条件满足后通过 Continuation 恢复 → 返回或异常 → Job 处理完成及子活动关系。继续逻辑和 dispatcher 的执行位置规则共同决定下一步。
|
||||
|
||||
## 12. Julia
|
||||
|
||||
**入口与执行者。** Julia REPL、脚本及 `include` 可以执行顶层代码。解析、宏展开和 lowering 后,由运行时选择解释或编译等路径处理;函数定义增加方法,不意味着当场执行函数体。调用根据方法分派选择逻辑,运行时可编译相应专门化。[Julia 执行路径](https://docs.julialang.org/en/v1/devdocs/eval/)
|
||||
|
||||
| 结构 | 保存什么 | 生命周期及归属 |
|
||||
| --- | --- | --- |
|
||||
| Module、方法及专门化相关表示 | 绑定、方法逻辑和可执行代码 | Julia 运行时管理 |
|
||||
| 普通调用状态 | 参数、局部状态和返回关系 | 一次调用 |
|
||||
| Task | 可暂停执行状态、结果及活动关系 | 由程序创建、运行时调度 |
|
||||
| Channel 和等待者 | 通信内容及等待关联 | 任务与 Channel 协议管理 |
|
||||
| 运行时值表示 | 值、类型及必要的对象头等 | 运行时管理;优化后的值不保证均是单独装箱对象 |
|
||||
|
||||
Julia 的 `jl_value_t` 等是实现层的对象表示;它回答值怎样存储,不决定哪个函数什么时候被调度。实现文档的历史细节不能直接充当完整稳定 ABI。[Julia 对象布局](https://docs.julialang.org/en/v1/devdocs/object/)
|
||||
|
||||
**进入与等待。** 创建 `Task` 不立即执行其函数体;需要调度或其他推进安排。`@async`、`Threads.@spawn` 等宏会创建并安排任务,但执行位置约束不同。`wait`、Channel 等可以让当前任务等待,运行时安排其他工作;暂停后保留状态,不从函数开头重新运行。[Julia 异步编程](https://docs.julialang.org/en/v1/manual/asynchronous-programming/)
|
||||
|
||||
**结束与关键词。** `return` 或异常结束本次调用,`try/finally` 关联退出清理。GC 与外部资源关闭分开处理;`do` 可把函数传给资源管理 API,具体关闭保证取决于被调用的 API。`Task`、`schedule`、`wait`、`Channel` 及这些宏不因为参与生命周期就都变成关键词。
|
||||
|
||||
典型轨迹:创建 Task → 调度 → 执行函数体 → wait/通信形成等待 → 条件满足后继续 → 返回或失败,等待者取得相应结果。Task 对象及结果可以在活动结束后继续被引用。
|
||||
|
||||
## 横向比较:什么动作真正进入执行
|
||||
|
||||
下表只比较所述常见用法。对象创建、提交调度和获得执行机会之间,不能用同一个“启动”掩盖差别。
|
||||
|
||||
| 用法 | 这一动作的直接效果 | 下一步由谁推进 |
|
||||
| --- | --- | --- |
|
||||
| 各语言的普通同步函数调用 | 当前执行路径进入函数体 | 当前线程/执行引擎继续 |
|
||||
| Python `async def` 调用 | 创建 coroutine,未执行函数体 | await、Task 等驱动 |
|
||||
| JavaScript `async` 调用 | 执行同步前缀,返回 Promise | 引擎及宿主协作推进异步继续 |
|
||||
| C# 常规 `async Task` 调用 | 同步推进,必要时在未完成 awaitable 处暂停 | 状态机、awaiter 与上下文策略 |
|
||||
| Rust `async fn` 调用 | 创建 Future | await 或 executor 的 poll |
|
||||
| C++ 协程调用 | 建立协程协议及状态,首次暂停规则由 promise 决定 | 调用者、awaiter 或库的 scheduler |
|
||||
| Go `go` 语句 | 求值调用信息并启动新的 goroutine | Go runtime 调度 |
|
||||
| Swift async 调用 | 在当前任务中调用可暂停函数;不必创建新 Task | Swift 并发执行机制 |
|
||||
| Kotlin suspend 调用 | 在可暂停调用链中执行;不必创建新 Job | Continuation 与协程上下文 |
|
||||
| Julia `Task` 构造 | 创建任务,未运行函数体 | 调度及运行时推进 |
|
||||
| React 状态更新 | 请求一次界面更新,不等于直接执行每个 Effect | React 组织渲染与提交,宿主提供执行机会 |
|
||||
|
||||
## 生命周期设计的比较结论
|
||||
|
||||
以下是基于上面机制的分析归纳,不是任何语言的统一规范。
|
||||
|
||||
- **循环不是所有生命周期的必要形式。** C++ 自动对象可以随作用域构造和析构;普通调用可以直接进入并返回。循环适合持续接受工作,但不定义全部存续关系。
|
||||
- **钩子不是全部调度机制。** 钩子连接条件与逻辑;优先级、执行位置、等待及取消还需要独立规则。命名回调、函数参数、订阅和协程继续位置是不同的连接形式。
|
||||
- **Task 不等于整个对象体系。** 数据值、代码定义、一次执行、结果句柄和长期组件应分别说明。可以共享基础对象模型,但不能因此共享同一执行状态机。
|
||||
- **宏任务/微任务是特定宿主的顺序契约。** 是否采用此类分层,应由可观察顺序、更新边界及响应性需求决定,不能从“需要循环”直接推出。
|
||||
- **长期保存定义不等于长期执行。** 会话、模块、平台对象和订阅都可以存续而暂时没有用户代码运行。
|
||||
|
||||
Endorphin 已有的阶段定义见 [Preflight 与 inflight](../guide/05-preflight-and-inflight.md),普通调用见[函数与调用](../guide/09-functions-and-calls.md),会话提案见 [REPL](../guide/14-repl.md)。需要进一步明确的执行契约集中在[框架比较后的设计分析](framework-runtime-lifecycles.md#对-endorphin-执行模型的设计分析)。
|
||||
|
||||
[关键词手册](language-keywords.md) · [框架如何接管代码执行](framework-runtime-lifecycles.md) · [返回目录](../README.md)
|
||||
@@ -7,9 +7,11 @@
|
||||
| 主题 | 已确定内容 |
|
||||
| --- | --- |
|
||||
| 语言定位 | 前后端共用的云原生编程语言,UI 是应用领域之一 |
|
||||
| 资源归属 | 每项独立登记的资源属于一个 workspace 和至少一级 namespace;用户是操作与作者身份 |
|
||||
| 资源归属 | workspace 管理归属与协作,namespace 提供命名入口;用户是操作与作者身份 |
|
||||
| 资源身份 | 独立 ID 识别资源;多个 namespace 可引用同一资源,命名入口变化不改写已保存的确定引用 |
|
||||
| 资源保留 | 从有效保留根可达的资源不能回收;移除命名入口不等于删除资源,需处理无人使用的循环引用 |
|
||||
| Workspace 命名 | workspace handle 在平台内唯一并参与 key,workspace 显示名可以重复;用户登录标识不作为资源归属前缀 |
|
||||
| namespace | 各层语义一致;以外部 key 检索,不在正文声明自身归属;函数、class、agent 和独立保存的基础内容共用资源归属体系 |
|
||||
| namespace | 各层语义一致;以外部 key 检索,不在源码声明自身归属;函数、class、agent 和独立保存的基础内容共用资源归属体系 |
|
||||
| key 形式 | `workspace handle:namespace路径`,冒号分隔 workspace 与路径,点号分隔层级 |
|
||||
| 用户与 workspace | 注册时创建默认个人 workspace,创建用户成为管理员;用户可以参与多个 workspace,workspace 可以包含多个用户 |
|
||||
| 授权边界 | workspace 整体授权,内部 namespace、class 和函数不各自维护用户访问名单;代码可视域独立处理 |
|
||||
@@ -26,6 +28,13 @@
|
||||
| Agent 编程 | agent 可以实现新逻辑并引用已有函数;提交新定义后须经过 Preflight 才能作为已就绪定义执行 |
|
||||
| 人工在环 | 高风险操作执行前暂停,等待人类确认或修改意见,并保留恢复所需状态 |
|
||||
| 类型兼容 | 用户声明的类型按声明身份区分,不仅凭字段或方法相同建立兼容或能力实现关系;不采用结构类型兼容 |
|
||||
| Object 与 Type | Object 是无父类型的继承根;Object 是 Type 的实例,Type 是自己的实例且继承 Object;平台按具体类型管理对象生命周期 |
|
||||
| 实例化与继承 | 对象的直接实例类型与类型的父类型分别保存和查询;类型对象与运行实例都属于对象体系 |
|
||||
| 定义构造入口 | class、trait、record、agent 等入口自身也是对象,构造出的类型或定义同样是对象;不预先将入口名称定为保留关键字 |
|
||||
| Object 与 atom | atom 是对象可独立识别、保存和引用的资源单元,资源 ID 连接对象图;组合对象也可以成为 atom |
|
||||
| 类型能力 | 在 Object 共同基础上组合多个显式 trait 能力,不要求以一条父子继承链表达全部能力;具体声明规则待定 |
|
||||
| 类型系统范围 | 基础类型、容器、引用和定义资源共同组织 class、Function、agent 等高级结构;讨论不限于函数签名 |
|
||||
| Function | 平台原生的函数类型,可扩展行为与生命周期;函数自身类型与调用返回类型分别表达 |
|
||||
| 调用目标 | 普通逻辑调用表达输入、结果与依赖,系统组织执行 |
|
||||
| 权限操作分工 | r 读取、w 编辑资源内容或定义、x 使用已定义的程序能力;程序按业务契约产生写入不要求调用者因此成为 Editor;执行不自动授予管理能力 |
|
||||
| 官方组件 | 官方 UI 组件与用户库内容分别定义 |
|
||||
@@ -36,20 +45,23 @@
|
||||
| 资源访问 | 客户端可查看获准访问的资源,依据当前资源或调用结果的类型选择呈现方式 |
|
||||
| 函数查看与调用 | 必填参数未就绪时查看函数本身;输入满足调用要求后可调用并呈现结果;执行等待不退回为定义查看 |
|
||||
| 跨端使用 | 函数调用与 hook 关联由平台组织执行和通信,应用直接使用符合声明类型的结果与更新 |
|
||||
| 跨端对象 | 对象可由平台管理和存储;客户端建立关联同一资源身份的本地副本,通过网络取得数据并同步后续变化;身份关联不表示共享内存或瞬时一致 |
|
||||
|
||||
## 收录的语法提案
|
||||
|
||||
| 提案 | 正文位置 | 说明 |
|
||||
| 提案 | 主要说明 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 词法与字面量 | [第 6 章](../guide/06-lexical-structure.md) | 本书统一采用的标识符、字符串、数字和符号形式 |
|
||||
| 类字段、成员与类型标注 | [第 7 章](../guide/07-types-and-classes.md) | 统一数值暂用 Number,文本沿用 String;类字段与成员函数的具体形式仍为提案 |
|
||||
| 表达式与 let | [第 8 章](../guide/08-expressions-and-bindings.md) | 基础运算、成员访问与局部绑定 |
|
||||
| function 与 return | [第 9 章](../guide/09-functions-and-calls.md) | 函数签名、基本函数体与调用组合 |
|
||||
| function 与 return | [第 9 章](../guide/09-functions-and-calls.md) | 早期基本调用草案;表达具体函数自身类型的替代声明见第 7 章候选 |
|
||||
| 顶级类型代码示例 | [第 7 章续篇](../guide/07-top-level-types/README.md) | 七组类型逐项展示候选声明、构造、调用与结果;函数声明同时比较两种形式,未合并进正式 EBNF |
|
||||
| Product.get | [第 10 章](../guide/10-data-access.md) | 读取体验提案,不是 class 自动附带的 API |
|
||||
| 组件效果 | [第 12 章](../guide/12-ui-components.md) | 参数、布局与默认值的效果提案;构造表达式尚未定义 |
|
||||
| agent 声明骨架 | [第 13 章](../guide/13-agents.md) | agent 语言地位已确定;共有成员骨架为提案,职责关联形式尚未定义 |
|
||||
| REPL 会话行为 | [第 14 章](../guide/14-repl.md) | 会话上下文、输入求值、对象查看、执行记录及同步状态的设计提案,不增加已确定的控制命令或顶层文法 |
|
||||
|
||||
程序声明组合与[形式文法](formal-grammar.md)同样属于设计稿。正文中的陈述定义这些提案内部的用法,不将其确定程度提升为最终规范。
|
||||
程序声明组合与[形式文法](formal-grammar.md)同样属于设计稿。语法提案按其内部规则使用,不等于最终规范。
|
||||
|
||||
## 身份与权限
|
||||
|
||||
@@ -78,7 +90,7 @@ workspace 归属、key 前缀和整体授权模型已确定。名称细节、配
|
||||
- 仅具有 x 时的调用接口信息范围,以及程序运行能力与资源编辑权限之间的具体执行机制。
|
||||
- 角色变更和授权撤销对正在执行、暂停或恢复中的调用、实例与任务的影响。
|
||||
|
||||
正文的 atelier、market key 前缀均解释为 workspace handle;alice、bob 仅在成员和作者示意中代表用户。
|
||||
示例中的 atelier、market key 前缀均为 workspace handle;alice、bob 在成员和作者示意中代表用户。
|
||||
|
||||
## 引用与代码视图
|
||||
|
||||
@@ -89,7 +101,7 @@ workspace 归属、key 前缀和整体授权模型已确定。名称细节、配
|
||||
- 视图顺序、版本选择、成员一致性及编辑操作映射。
|
||||
- key 的传递编码和索引关联机制。
|
||||
|
||||
正文跨 namespace 示例采用目标声明可见、名称可直接解析且无冲突的条件;该条件不代替正式名称查找规则。
|
||||
跨 namespace 示例采用目标声明可见、名称可直接解析且无冲突的条件;该条件不代替正式名称查找规则。
|
||||
|
||||
## 声明与类型
|
||||
|
||||
@@ -103,7 +115,30 @@ workspace 归属、key 前缀和整体授权模型已确定。名称细节、配
|
||||
- 代码更新和不同版本之间的类型身份比较规则。
|
||||
- 重复声明、完整控制流、实例及字段可变性、赋值和作用域细节。
|
||||
|
||||
本文简单函数体仅收录 let 与末尾 return,不意味着整门语言只允许这两种语句。
|
||||
第 9 章的基本调用草案只展示 let 与末尾 return;第 7 章的类型设计另有赋值、等待等候选示例,两者都不穷尽语言语句。
|
||||
|
||||
## 顶级类型讨论
|
||||
|
||||
[Object 与类型系统](../guide/07-top-level-types/README.md)定义对象、类型对象及其资源关联。Object/Type 闭环、实例化线与继承线、资源 atom 关系和平台生命周期职责已确定;各类型的完整操作、源码接口与能力接入形式仍分别评审。
|
||||
|
||||
| 类型组 | 已确定方向 | 候选与待定范围 |
|
||||
| --- | --- | --- |
|
||||
| [Object](../guide/07-top-level-types/README.md#object) | Object ∈ Type、Type ∈ Type、Type ⊆ Object;实例化与继承关联接入资源 ID 图 | 共同操作接口、typeOf 与 basesOf 的具体形式、能力分派、继承语法及登记粒度 |
|
||||
| [Bool、Number、String、Unit、Null](../guide/07-top-level-types/values.md) | 统一数值、文本与基础常量模型 | Bool、Unit、Null 的地位;基础类型怎样约束结构成员、精度与转换 |
|
||||
| [Tuple、record、List、Map、Set、Option、Result](../guide/07-top-level-types/collections.md) | 需要组合固定成员、容器和分支结构 | 类型构造与参数规则、名义身份、相等性与可变性;Option 和 Result 为候选 |
|
||||
| [Ref、Cell](../guide/07-top-level-types/references.md) | 独立资源 ID、确定引用与可变目标引用;按保留根可达性回收 | 显式类型与透明引用的关系、解析时机、保留根和状态引用规则 |
|
||||
| [Type、Trait、Code、class](../guide/07-top-level-types/definitions.md) | 类型本身是 Type 对象,可传递和引用;代码也是对象;名义类型与多个 trait 能力组合 | 构造入口的具体类型和语法、成员组合、反射和生成规则 |
|
||||
| [Function](../guide/07-top-level-types/functions.md) | 原生函数类型,可扩展行为和生命周期;自身类型与返回类型分别表达 | 完整声明语法、扩展机制、捕获环境、实例状态与调用生命周期 |
|
||||
| [Task、Stream、State、Session](../guide/07-top-level-types/execution.md) | inflight 管理运行实体及状态 | 是否独立原生化、内容类型参数,以及等待、取消、恢复和共享规则 |
|
||||
| [Agent、agent](../guide/07-top-level-types/agents.md) | Agent 是 Type 的实例并继承 Object;具体类型对象与运行实例分别保存 | 具体类型继承 Agent 的形式、构造入口、成员组合及运行生命周期 |
|
||||
|
||||
资源 ID 独立于命名入口:workspace 管理归属与协作,namespace 管理组织,同一资源可以具有多个命名入口;移除入口不等于清除仍被保留程序引用的资源。namespace key 中的非空路径要求只描述命名入口,不要求资源始终保留一个入口,也不充当资源 ID 的定义。具体登记及名称绑定机制仍待确定。
|
||||
|
||||
atom 是 Object 的资源组织视角,不另外引入 Atom 基础类型。定义对象及实例对象分别保留具体身份与生命周期;运行对象的固定 ID 不冻结其合法状态变化。workspace 与 namespace 的管理职责和资源 atom 分开,不因共同对象模型自动把管理记录变成语言资源。
|
||||
|
||||
函数构造必须区分自身类型与调用签名,具体简写尚未确定。trait 组合方向不自动引入 Rust 的其他规则。完整泛型与遗传算法设计尚待定义。
|
||||
|
||||
候选示例采用类型参数、箭头签名、显式实现、构造器及任务操作,其状态不构成实现或可执行性保证。
|
||||
|
||||
## 基础资源与变量
|
||||
|
||||
@@ -128,7 +163,7 @@ workspace 归属、key 前缀和整体授权模型已确定。名称细节、配
|
||||
|
||||
- 定义创建、更新与退出可用范围的接口,以及已有调用或实例对版本的选择。
|
||||
- 多定义修改的一致性、协作冲突处理和运行中提交代码的可见时机。
|
||||
- 定义删除对已有引用、对象和 agent 实例的影响。
|
||||
- 删除内容、撤销授权与已有对象或 agent 实例的关系;仅移除命名入口不会使保留的确定引用失效。
|
||||
- 临时值、不可达值与实例的回收时机,持久保存的数据及记忆的保留、归档与删除规则。
|
||||
- 运行状态暂停、保存和恢复时引用与版本的一致性。
|
||||
|
||||
@@ -142,7 +177,7 @@ workspace 归属、key 前缀和整体授权模型已确定。名称细节、配
|
||||
- 换行字符、字符串扩展转义、更多字面量和运算符。
|
||||
- 数值精度与舍入、除法、隐式转换与所有调用参数的求值顺序;不按固定机器位宽定义数值溢出。
|
||||
|
||||
正文中同级二元算术运算的组合顺序属于表达式提案,不规定所有调用的执行顺序。
|
||||
同级二元算术运算从左到右组合属于表达式提案,不规定所有调用的执行顺序。
|
||||
|
||||
## 调用与数据
|
||||
|
||||
@@ -150,13 +185,30 @@ workspace 归属、key 前缀和整体授权模型已确定。名称细节、配
|
||||
|
||||
- 显式等待、失败处理、缺失值、取消和超时的源码形式。
|
||||
- 数据读取成员的声明、参数与结果类型。
|
||||
- 一次结果、持续结果及其更新语义。
|
||||
- 一次读取与持续关联的表达式、结果类型及建立方式;对象同步的具体边界见下一节。
|
||||
- hook 的源码形式、触发或订阅关系、生命周期、关联解除和更新范围。
|
||||
- 带业务修改的调用顺序、重复执行限制与失败行为。
|
||||
- 更新代码时已有调用使用哪个版本。
|
||||
- 已有调用继续保留所选定义,切换新定义或迁移运行实例的显式机制仍待定。
|
||||
|
||||
正常结果必须符合声明,未就绪或失败不能伪造为成功结果。Product.get 示例只展示成功路径。
|
||||
|
||||
## 跨端对象与同步
|
||||
|
||||
主要定义见[跨端对象与同步](../guide/11-resource-access-and-presentation.md#117-跨端对象与同步)。平台管理和存储对象、客户端建立本地副本并关联远程对象、通过网络交付数据及后续同步的方向已确定。它沿用 Object、资源 ID、类型及生命周期模型,不另设 PlatformObject 基础类型,也不自动把 class 变成持久化表。
|
||||
|
||||
不可变内容或定义更新产生新资源身份,确定引用不因同步而改指新对象;运行对象可以在类型允许的范围内保留身份并改变状态。平台对象、本地副本与同步关联分别具有生命周期,释放副本不等于删除平台对象。
|
||||
|
||||
尚未定义:
|
||||
|
||||
- 对象的登记与加载范围、本地副本的源码形式,以及完整或部分数据的取得规则。
|
||||
- 一次读取与持续关联的建立、解除、可写性和结果类型;hook 与对象同步的具体关联方式。
|
||||
- 状态版本、读取新鲜度、更新顺序及多对象一致性契约;不预先选定服务器权威、版本比较或合并算法。
|
||||
- 本地修改的提交与保存确认、等待与失败状态,以及是否允许提前展示尚未被平台接受的修改。
|
||||
- 多端同时修改的冲突处理、重试、去重和重复业务效果限制。
|
||||
- 离线期间的读写、断线后的恢复、遗漏更新的取得及重新同步规则。
|
||||
- 授权撤销、目标删除、关联解除与资源回收对已有副本的影响。
|
||||
- 传输协议、类型编码及对象存储后端;这些实现选择不由逻辑对象身份决定。
|
||||
|
||||
## UI
|
||||
|
||||
尚未定义:
|
||||
@@ -168,7 +220,7 @@ workspace 归属、key 前缀和整体授权模型已确定。名称细节、配
|
||||
- 布局单位、参数范围、负数、显式尺寸、约束与溢出。
|
||||
- 主题、样式、文字测量和其他组件。
|
||||
|
||||
正文的官方组件示例使用结构示意,不定义调用语法,也不承诺免导入使用。
|
||||
官方组件示例使用结构示意,不定义调用语法,也不承诺免导入使用。
|
||||
|
||||
## 资源访问与呈现
|
||||
|
||||
@@ -177,7 +229,7 @@ workspace 归属、key 前缀和整体授权模型已确定。名称细节、配
|
||||
保留待讨论:
|
||||
|
||||
- 完整顶级类型的名称、集合及关系;已确定基础数值、文本、媒体和 GIS 类别,不代表完整类型层次已经确定。
|
||||
- 顶级类型采用继承、接口、协议或其他机制的关系与声明形式。
|
||||
- trait 能力组合及原生类型扩展的完整关系与声明形式。
|
||||
- 可渲染类型的契约、普通类型的默认展示方式及自定义呈现。
|
||||
- 同一资源具有多种呈现能力时的选择规则及未知类型的处理方式。
|
||||
- 参数填写、默认或可省略参数、平台提供参数与访问触发调用的具体规则。
|
||||
@@ -201,15 +253,38 @@ Agent 的语言资源地位、共有成员模型和核心职责已确定,主
|
||||
|
||||
成员函数是否默认向模型暴露为工具仍待定义;引用定义不自动启动实例或任务。MemorySaver 等外部库 API 不成为语言关键字或默认成员。
|
||||
|
||||
## REPL
|
||||
|
||||
[交互式会话(REPL)](../guide/14-repl.md)提出持续输入环境:声明准备定义,表达式检查后求值,结果对象可在后续输入中继续使用,远程等待与同步状态可查看。提案复用已有对象、权限、Preflight/inflight 和资源呈现规则;会话范围绑定、定义暂存、结果保留及交互调度尚未确定为正式契约。
|
||||
|
||||
尚未定义:
|
||||
|
||||
- 启动入口、控制命令、快捷键、多行输入边界、完整 REPL 文法及顶层绑定的正式形式。
|
||||
- 会话名称的作用域、重复声明、重新绑定、失败后的环境变更,以及导入与名称冲突处理。
|
||||
- 临时定义的资源登记、保存范围、共享 namespace 的编辑接口及新旧定义的绑定切换。
|
||||
- 是否采用原生 Session、身份及权限传播、会话隔离与上下文切换。
|
||||
- 输入的顺序与并发调度、待完成结果的引用、取消确认及未完成调用的结束行为。
|
||||
- 结果查看方式、显式结果命名、更新通知与同步状态呈现;不预先引入隐式结果变量。
|
||||
- 历史与会话状态的保存、对象保留根、恢复规则,以及避免业务调用被自动重放的具体契约。
|
||||
- 断线、授权变化、客户端退出对平台任务、副本、同步关联及保存结果的影响。
|
||||
|
||||
本章的交互示意按文档规则推演,不代表已有启动命令或实际执行结果。REPL 提案不改写函数声明、普通调用和跨端对象的已有语义,也不选择存储后端或调度实现。
|
||||
|
||||
## 设计决定记录
|
||||
|
||||
2026-10-08 的用户设计决定明确了定义与运行时的 Preflight/inflight 生命周期、agent 作为语言结构及其核心职责,以及基础常量资源、统一数值、格式归一化和变量引用模型。未明确的关键字、成员关联、算术和编码选择继续保留为提案或未定义项。
|
||||
|
||||
同日确认 w 用于资源编辑,x 用于使用定义好的程序能力,业务调用产生写入不要求调用者成为 Editor。随后明确采用 workspace 归属模型:key 使用 workspace handle,注册创建默认个人 workspace,用户作为成员、操作用户及作者,权限按 workspace 整体管理。此决定替换原用户名归属模型;名称细节、迁移和仅执行授权等未定项不随之确定。
|
||||
|
||||
2026-10-09 的用户决定明确类型系统用于组织高级结构,类型标题使用代码中的名称。Unit、Null、Option、Result、State 等候选是否原生化、各项语法如何表达,仍需分别确定。
|
||||
|
||||
同日确定一切皆对象模型及 Object/Type 闭环:Object 是 Type 的实例,Type 是自己的实例并继承 Object,Object 没有父类型。实例化、继承和普通资源引用分别保存;class、trait、record、agent 构造入口自身也是对象。模型与资源 atom、独立 ID、确定引用及可达性保留统一。反射接口、构造入口类型、生命周期接入语法和登记粒度继续待定。
|
||||
|
||||
2026-10-13 的用户决定明确了平台管理和存储对象的方向:客户端获取远程数据时建立关联远程对象的本地对象,实际数据通过网络传递,并在后续保持同步。该方向纳入已有对象与资源身份模型;具体源码接口、保存确认、版本、冲突、离线及存储实现继续待定。
|
||||
|
||||
## 规范范围
|
||||
|
||||
本文定义源码及应有的语言效果。云端实体、持久化类、自动建表、通信、缓存、部署和编排实现不在本阶段规范中。
|
||||
本文定义源码及应有的语言效果,包括平台对象存储、跨端副本关联与同步的概念边界。云端实体的实现、持久化类、自动建表,以及存储、通信、缓存、部署和编排的实现方案不在本阶段规范中。
|
||||
|
||||
S3 约定仅用于代码存储,不规定业务数据后端。平台负责跨端执行与通信的约定不指定传输协议、类型编码、调度算法或部署产物。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user