此编程语言功能的名称是什么?是否有任何支持它的真实语言?

What is the name of this programming language feature and are there any real-world languages that support it?

让树数据结构这样定义:

一棵树有一个节点作为它的根。一个节点要么是一片叶子,要么是一个内部节点,它有一个或多个节点作为其子节点。

在某种伪 OO 编程语言中,我们可以这样定义一棵树:

Node := InnerNode | Leaf

Leaf {

    isLeaf() : TRUE

}

InnerNode {

    isLeaf() : FALSE
    children() : List<Node>

}

Tree {
    root() : Node
}

现在我们可以定义两个函数,'bad_code'和'good_code'。函数 'bad_code' 不编译,另一个函数编译:

function bad_code(Node anyNode) : void {

    // this will give a compile time error "type Node does not define method children()"
    anyNode.children();
}

function good_code(Node anyNode) : void {

    // the compiler understands that all Nodes must have a method called isLeaf() which 
    // returns a boolean
    let b : boolean <- anyNode.isLeaf();

    if (b == FALSE) {

        // this will not give a compile time error because the compiler can deduce that 
        // anyNode must be of type InnerNode which has the method children()
        anyNode.children();
    }
}

问题:

  1. 以上是否是以某种官方方式定义/描述的语言特性的示例?
  2. 如果是这样:这个语言功能的正式名称是什么?
  3. 现实世界中是否有实现此语言功能的编程语言?
  4. 此语言功能是否可以在运行时以零成本的编译时检查来实现?

你所描述的是编译器使用控制流图来缩小变量的类型,因此当 if 语句测试与变量类型相关的条件时,可以为 if 语句的主体推断出同一变量的更具体类型。

这称为控制流类型缩小,例如在Typescript。它纯粹是静态检查,在编译时完成,没有运行时损失;事实上,Typescript 中的类型在运行时根本不可用。

type TreeNode = InnerNode | Leaf

interface Leaf {
    isLeaf: true
}

interface InnerNode {
    isLeaf: false
    children: Node[]
}

function bad_code(anyNode: TreeNode): void {
    // type error: Property 'children' does not exist on type 'TreeNode'.
    console.log(anyNode.children);
}

function good_code(anyNode: TreeNode): void {
    if (!anyNode.isLeaf) {
        // narrowed type to anyNode: InnerNode
        console.log(anyNode.children);
    }
}

请注意,Typescript 要求您以特定方式执行此操作;我们直接测试 anyNode.isLeaf 而不是先将其存储在变量 b: boolean 中,因为 Typescript 不会跟踪两个变量 banyNode 之间的关系:

function bad_in_typescript(anyNode: TreeNode): void {
    let b: boolean = anyNode.isLeaf;

    if (!b) {
        // type error: Property 'children' does not exist on type 'TreeNode'.
        console.log(anyNode.children);
    }
}

此外,在上面的代码中 isLeaf 是一个 属性 而不是方法。 Typescript 确实有一个名为 user-defined type guards 的相关特性,它允许方法的 return 类型类似于 this is Leaf,表明方法 returns true 仅当调用类型为 Leaf:

type TreeNode = InnerNode | Leaf

interface BaseNode {
    ifLeaf(): this is Leaf
    isInner(): this is InnerNode
}

interface Leaf extends BaseNode {}

interface InnerNode extends BaseNode {
    children(): Node[]
}

但是,Typescript 仍然比您的示例更受限制;我们必须测试 anyNode.isInner() 因为 !anyNode.isLeaf() 不一定会做同样的缩小。 (打字稿使用结构类型,所以实际上这个 LeafInnerNode 的超类型,这会导致联合类型出现一些问题。如果你给 Leaf 一个 属性 像 value: numberInnerNode 没有,那么 !anyNode.isLeaf() 将按照您的预期工作。)