为什么很多编程语言都将*类型放在变量名之后?

Jas*_*ker 15 grammar programming-languages language-design

我刚刚在Go FAQ中遇到过这个问题,它让我想起了一段时间以来一直困扰着我的事情.不幸的是,我真的没有看到答案的答案.

似乎几乎所有非C类语言都将类型放在变量名后面,如下所示:

var : int
Run Code Online (Sandbox Code Playgroud)

出于纯粹的好奇心,这是为什么?选择其中一个是否有优势?

Ste*_*314 12

正如Keith Randall所说,有一个解析问题,但这不是他所描述的."不知道它是一个声明还是一个表达式"根本无关紧要 - 在你解析整个事情之前,你不关心它是一个表达式还是一个声明,此时模糊性得到了解决.

使用无上下文解析器,无论类型是在变量名之前还是之后,都无关紧要.重要的是,您不需要查找用户定义的类型名称来理解类型规范 - 您不需要了解之前的所有内容以了解当前令牌.

Pascal语法是无上下文的 - 如果不是完全的话,至少WRT这个问题.变量名首先出现的事实不如冒号分隔符和类型描述语法等细节重要.

C语法是上下文相关的.为了使解析器确定类型描述的结束位置以及哪个标记是变量名,它需要已经解释了之前的所有内容,以便它可以确定给定的标识符标记是变量名还是只是另一个标记类型描述.

因为C语法是上下文敏感的,所以使用传统的解析器生成器工具(如yacc/bison)解析非常困难(如果不是不可能),而使用相同的工具很容易解析Pascal语法.也就是说,现在有解析器生成器可以处理C甚至C++语法.虽然它没有正确记录或在1.?发布等,我个人最喜欢的是Kelbt,它使用回溯LR并支持语义"撤销" - 当推测性解析结果出错时,基本上撤消对符号表的添加.

在实践中,C和C++解析器通常是手写的,混合递归下降和优先解析.我认为这同样适用于Java和C#.

顺便提一下,C++解析中与上下文敏感性类似的问题已经造成了很多恶意.C++ 0x 的" 替代函数语法 "通过将类型规范移到最后并将其放在分隔符之后来解决类似问题 - 非常类似于函数返回类型的Pascal冒号.它没有摆脱上下文敏感性,但采用类似Pascal的约定确实使它更易于管理.


Luk*_*fer 11

你说的"最其他"语言是那些更具说明性的语言.它们旨在让您按照自己的想法进行更多编程(假设您没有陷入命令式思考).

type last读作'创建一个名为NAME TYPE类型的变量'

当然,这就是说'创建一个名为NAME的TYPE',但是当你想到它时,值的重要性比类型更重要,类型只是对数据的编程约束


Gyö*_*sek 8

如果变量的名称从第0列开始,则更容易找到变量的名称.

相比

QHash<QString, QPair<int, QString> > hash;
Run Code Online (Sandbox Code Playgroud)

hash : QHash<QString, QPair<int, QString> >;
Run Code Online (Sandbox Code Playgroud)

现在想象一下你的典型C++标题的可读性有多大.


Mar*_*ing 8

增加的趋势是根本不说明类型,或者可选地说明类型.这可以是动态类型语言,其中变量上确实没有类型,或者它可以是静态类型语言,它从上下文中推断出类型.

如果有时给出类型并且有时推断出类型,那么如果后面有可选位,则更容易阅读.

还有一些趋势与语言是否认为自己来自C学校或功能学校或其他什么相关,但这些都是浪费时间.改善其前辈并且值得学习的语言是那些愿意接受来自所有不同学校的基于优点的输入的语言,而不是对特色遗产的挑剔.


Edm*_*und 6

在形式语言理论和类型理论中,它几乎总是写成var: type.例如,在类型化的lambda演算中,您将看到包含以下语句的证明:

x : A   y : B
-------------
 \x.y : A->B
Run Code Online (Sandbox Code Playgroud)

我认为这不重要,但我认为有两个理由:一个是"x:A"是"x是A型",另一个是类型就像一个集合(例如int是集合)整数),符号与"xεA"有关.

其中一些东西早于您正在考虑的现代语言.


cay*_*ann 5

"那些不记得过去的人被谴责重复过去."

将变量放在变量之前与Fortran和Algol完全无关,但它在C中变得非常难看,其中一些类型修饰符在变量之前应用,其他类型之后应用.这就是为什么在C你有这样的美女

int (*p)[10];
Run Code Online (Sandbox Code Playgroud)

要么

void (*signal(int x, void (*f)(int)))(int)
Run Code Online (Sandbox Code Playgroud)

与实用程序(cdecl)一起,其目的是解密这种乱码.

在Pascal中,类型位于变量之后,因此第一个示例变为

p: pointer to array[10] of int
Run Code Online (Sandbox Code Playgroud)

对比

q: array[10] of pointer to int
Run Code Online (Sandbox Code Playgroud)

在C中,是

int *q[10]
Run Code Online (Sandbox Code Playgroud)

在C中,您需要使用括号将其与int(*p)[10]区分开来.Pascal中不需要括号,只有订单才有意义.

信号功能将是

signal: function(x: int, f: function(int) to void) to (function(int) to void)
Run Code Online (Sandbox Code Playgroud)

还是满口,但至少在人类理解的范围内.

公平地说,问题不在于C将类型放在名称之前,而是它反过来坚持在名称之前放置点点滴滴,以及之后的其他部分.

但是如果你试图将所有内容放在名称之前,那么订单仍然是不直观的:

int [10] a // an int, ahem, ten of them, called a
int [10]* a // an int, no wait, ten, actually a pointer thereto, called a
Run Code Online (Sandbox Code Playgroud)

因此,答案是:一个合理设计的编程语言将变量放在类型之前,因为结果对于人类来说更具可读性.