代码之家  ›  专栏  ›  技术社区  ›  Colin Pickard

为什么要区分返回值的方法和不返回值的方法?

  •  5
  • Colin Pickard  · 技术社区  · 15 年前

    为什么有些语言区分返回值的方法和不返回值的方法?

    例如,在Oracle的pl/sql中,函数和过程的主要区别在于函数必须返回值,而过程不能返回值。

    同样的,对于那些没有的语言,为什么不呢?


    编辑:我发现了一个相关问题,可能会让阅读此问题的人感兴趣:

    3 回复  |  直到 13 年前
        1
  •  26
  •   Randy Levy    14 年前

    因为在计算机科学理论和实践的最初概念中,函数和子程序实际上彼此没有任何关系。

    Fortran通常被认为是实现这两种语言并展示其区别的第一种语言。(早期的Lisp在这方面也有一些相反的作用,但在学术界之外几乎没有影响)。

    从数学的传统(CS仍然是60年代的一部分)来看,函数仅被视为参数化数学计算的封装,其目的仅仅是将值返回到更大的表达式中。你可以称之为“裸”(f=azimuth(seconds))只是一个微不足道的用例。

    另一方面,子程序被看作是命名一组具有某种效果的语句的一种方法。参数极大地提高了它们的可用性,允许它们返回修改后的参数值的唯一原因是,它们可以在不依赖全局变量的情况下报告它们的状态。

    所以,除了封装和参数,它们实际上没有概念上的连接。

    真正的问题是:“那么多开发人员是如何看待它们的呢?”

    答案是C。

    当K+R最初为PDP-11设计其高级宏汇编程序类型语言时(可能已在PDP-8上启动?)他们没有硬件独立的幻想。实际上,该语言的每个“独特”特性都反映了PDP机器语言和体系结构(参见i++和--i)。其中之一是实现函数和子例程可以(并且始终)在PDP中以相同的方式实现,除非调用方刚刚忽略子例程的返回值(r0[,r1])。

    因此诞生了空指针,在C语言接管了整个编程世界之后,人们错误地认为这个硬件/操作系统实现工件(尽管在随后的每个平台上都是这样)与语言语义相同。

        2
  •  3
  •   Doug McClean    15 年前

    在纯或效果类型的设置中,存在一个差异的世界,因为显然,“不返回任何内容”的方法只对它们的副作用有用。

    这类似于表达式和语句之间的区别,后者可以分解语言并消除一类通常是错误的程序(当然,这也是C不这样做的原因;)。

    举个小例子,当你清楚地区分表达式和语句时, if(x = 3) ,而不是 if(x == 3) 在语法上不正确(用于使用需要表达式的语句),而不仅仅是类型错误(用于使用需要布尔值的整数)。这也有不允许的好处 if(x = true) 在赋值是具有右操作数值的表达式的上下文中,基于类型的规则允许这样做。

    在一种用单子来封装效果的语言中,重要的区别在于:

    • 返回的函数 () 它是纯函数,只能返回一个调用的无用空值 () 或发散
    • 返回的函数 IO () (或其他monad中的单位),除IO(或两者中的任一)monad中的效果外,这些功能没有“结果”。
        3
  •  0
  •   Yttrill    13 年前

    对不起,我回答了一个两岁大的问题,尤其是用我自己的语言费利克斯特有的语言。 http://felix-lang.org 但不管怎么说,这里是:)

    在Felix中,函数和过程是基本不同的,不仅过程有副作用,而且在语句中被调用,而函数没有副作用,并且在表达式中使用(因为Felix也有生成器,它们是具有副作用的函数)。:)

    不,执行模型从根本上是不同的,主要是出于性能原因,但不是完全不同。模型是:

    • 函数把它们的返回地址放在机器堆栈上,返回值也放在上面。
    • 过程使用堆上的链接列表。过程代码是平面的,它不使用机器堆栈。

    这通常是低效的,为什么要这样做?答案是:Felix程序都是潜在的共同程序(纤维)。他们可以通过访问一个通道将控制切换到另一个过程。这会导致控制权的交换。

    • 出于性能原因,不能在控制交换上复制机器堆栈。
    • 出于内存管理的原因,交换堆栈指针也不是一个选项。

    操作系统通常将堆栈指针交换为线程,这是相当快的,但在线性地址机上有一个基本问题:要么将堆栈的最大大小限制为一个非常小的值,要么将线程数限制为一个非常小的值。在32位机器上,没有足够的地址空间来考虑这个解决方案。在64位机器上,堆栈交换具有更大的潜力,但当然,用户的需求总是在释放后的3天增长到超过硬件。:)

    Felix只是将一个指针交换到基于堆的堆栈,因此上下文切换速度非常快,浪费的地址空间非常少。 当然,成本是过程调用的堆分配。

    在编译器中,许多理论模型的体系结构都是在“假设”的基础上进行优化的,因此实际的性能和实现可能与理论模型有很大的不同,前提是编译器能够证明您不能分辨出不同之处。除了被剥夺了悠闲地喝一杯咖啡的机会之外:)

    因此,对于为什么函数和过程可能被不同地对待,您有不同的答案。

    推荐文章