作用域为调用堆栈的变量

variables that are scoped to a call stack

提问人:Giacomo Tagliabue 提问时间:2/9/2023 最后编辑:jaco0646Giacomo Tagliabue 更新时间:2/21/2023 访问量:67

问:

前提:这不是一个特定于特定语言的问题,而是一个通用的编程问题,以了解某些语言是否具有这种结构,如果没有,它的原因是什么,因为它看起来非常有用?

:什么是允许在调用堆栈级别声明变量的构造,以便只有该特定调用堆栈中的函数才能访问它?我将尝试使用 javascript 来强调这一点:

async function main() {
  await Promise.all([foo(), bar()])
}

async function foo() {
   await setTimeout(100);
   setting (const a = 1) {  // <===== set here
      await setTimeout(100);
      await baz();
   }
}

async function bar() {
   await setTimeout(100);
   setting (const a = 2) {  // <===== set here
      await setTimeout(100);
      await baz();
   }
}

async function baz() {
   const a = STACK_CONTEXT.a; // <===== used here
   console.log(a)
}

尽管这看起来像一个全局函数,但该函数仅在正在执行的特定调用堆栈下可用。我正在使用假设关键字来强调这一点。在该特定示例中,有 2 个并行运行的调用堆栈,其局部上下文变量“a”不同。这比向下输送变量要好(如果 bar 和 baz 之间有很多函数),并且由于显而易见的原因,使用线程局部或全局变量之类的东西会具有更好的属性。我还没有遇到过具有此功能的编程语言,但我想知道为什么,因为这在许多情况下非常有用。settingbar->baz()

设计模式 范围 全局变量 语言不可知

评论


答:

1赞 jaco0646 2/9/2023 #1

Java 20 添加了一个名为 Scoped Values 的孵化功能,它有点类似于 OP 示例,不同之处在于这些变量是不可变的(出于性能和安全考虑)。

JEP的最后一段提到了一些历史背景。

作用域值的灵感来自于许多 Lisp 方言为动态作用域自由变量提供支持的方式;特别是,这些变量在深度绑定的多线程运行时(如 Interlisp-D)中的行为方式。作用域值通过添加类型安全性、不可变性、封装和线程内和线程之间的高效访问来改进 Lisp 的自由变量。

所以这个想法是有先例的。

1赞 Matt Timmermans 2/21/2023 #2

这个想法被称为“动态范围”,与“词法范围”或“静态范围”形成鲜明对比,这是当今几乎所有编程语言都使用的。

请参见:https://www.geeksforgeeks.org/static-and-dynamic-scoping/

曾经有一些关于哪个更好的争论,你可以在一些古老的语言中找到动态范围——早期的 LISP、SNOBOL、APL 等。

不过,争论现在以另一种方式解决了。词法范围可以更容易地推理程序的工作方式。