头等对象(英语:First-class object),在计算机科学中,指称支持其他实体通常能获得的所有运算的实体。这些运算典型的包括:在执行期创造,作为参数传递给其他函数,或存入一个变数[1]。将一个实体变为头等对象的过程叫做“实化”(Reification)[2]

“头等对象”这一名称最早由克里斯托弗·斯特雷奇在1960年代发明,原称“头等公民”(First-class citizen),意指函数可作为电脑语言中的头等公民。英文中也称“First-class entity”或“First-class value”。

历史

头等对象和二等对象的概念,在1960年由克里斯托弗·斯特雷奇引入。[3][4] 实际上他并没有给出严格的术语定义,而是给出了ALGOL语言中实数和过程的对比:

头等对象和二等对象。在Algol程序语言中,一个“实数”可能会出现在一个表达式中或被赋给一个变量,并可能在过程调用中作为实际参数出现。而“过程”只可能会出现在另一个过程调用中,最常见的是作为操作符,有时候也作为实参。除此之外,没有表达式会涉及到过程,或者将过程作为计算结果。因此在某种意义上,在Algol程序语言中的过程是二等公民,它们总是会单独出现,不可能被一个表达式或一个变量表示(形式参数除外)…[5]

在1990年代,拉斐尔·芬克尔提出了二等值和三等值的定义[6],但这些定义尚未被广泛采用。[7]

定义

头等对象不一定是面向对象程序设计所指的物件,而可以指任何程序中的实体。Robin Popplestone英语Robin Popplestone给出如下定义:

  1. 所有项目都有特定的基本权力。
  2. 所有项目都可以作为函数的实际参数。
  3. 所有项目都可以作为函数的结果返回。
  4. 所有项目都可以是赋值语句的主体。
  5. 所有项目都可以等式测试。[8]

范例

最简单的标量数据类型,比如整数和浮点数,几乎总是头等的。在很多较早的语言中,数组和字符串不是头等的:它们不能被作为赋值的对象,或作为形式参数传递给子例程。例如,FORTRAN IVC都不支持数组赋值,并且它们在作为形式参数传递的时候,实际上只有它们的第一个元素的位置被传递了,它们的大小失去了。C看起来支持数组指针的复制,但实际上它们只是到数组的第一个元素的指针,仍然不承载这个数组的大小。

不同语言中对函数的区别很大,例如C语言C++中的函数不是头等对象,因为在这些语言中函数不能在执行期创造,而必须在设计时全部写好。相比之下,Scheme中的函数是头等对象,因为可以用lambda表达式来创造匿名函数并作为头等对象来操作。

More information 概念, 描述 ...
概念 描述 语言
头等函数 闭包匿名函数 Dart, Scheme, ML, Haskell, F#, Kotlin, Scala, Swift, Perl, PHP, Python, Raku, JavaScript, Delphi, Rust
头等控制 续体 Scheme, ML, F#
头等类型 依赖类型 Coq, Idris, Agda
头等数据类型 Generic Haskell, C++11
头等多态 非直谓多态
头等消息英语first-class message 动态消息(方法调用) Smalltalk[9], Objective-C[9], Common Lisp
头等类 元类 Smalltalk, Objective-C, Ruby, Python, Delphi, Common Lisp
头等证明 证明对象[10] Coq, Agda
Close

参考文献

Wikiwand in your browser!

Seamless Wikipedia browsing. On steroids.

Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.

Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.