我在Go常见问题解答中遇到了this question,它让我想起了一段时间以来一直困扰着我的事情。不幸的是,我真的没有看到答案的答案。
似乎几乎所有非C类语言都将类型放在变量名后面,如下所示:
var : int
出于纯粹的好奇心,这是为什么?选择其中一个是否有优势?
答案 0 :(得分:12)
使用无上下文解析器,无论类型是在变量名之前还是之后,都无关紧要。重要的是您不需要查找用户定义的类型名称来理解类型规范 - 您不需要理解之前的所有内容以了解当前令牌。
Pascal语法是无上下文的 - 如果不是完全的话,至少WRT这个问题。变量名首先出现的事实不如冒号分隔符和类型描述的语法等细节重要。
C语法是上下文相关的。为了使解析器确定类型描述的结束位置以及哪个标记是变量名,它需要已经解释了之前的所有内容,以便它可以确定给定的标识符标记是变量名还是只是另一个标记类型描述。
因为C语法是上下文敏感的,所以使用传统的解析器生成器工具(如yacc / bison)解析非常困难(如果不是不可能),而使用相同的工具很容易解析Pascal语法。也就是说,现在有解析器生成器可以处理C甚至C ++语法。虽然它没有正确记录或在1.?发布等,我个人最喜欢的是Kelbt,它使用回溯LR并支持语义“撤销” - 当推测性解析结果出错时,基本上撤消对符号表的添加。
实际上,C和C ++解析器通常是手写的,混合递归下降和优先解析。我认为这同样适用于Java和C#。
顺便说一句,C ++解析中与上下文敏感性类似的问题已经造成了很多恶意。 C ++ 0x的“Alternative Function Syntax”通过将类型规范移到最后并将其放在分隔符之后来解决类似问题 - 非常类似于函数返回类型的Pascal冒号。它没有摆脱上下文敏感性,但采用类似Pascal的约定确实使它更容易管理。
答案 1 :(得分:11)
你所说的“大多数其他”语言都是更具声明性的语言。他们的目标是让你按照自己的思路进行更多的编程(假设你没有陷入命令式思考)。
键入last read为'创建一个名为NAME TYPE'的变量
这当然与说“创建一个名为NAME的TYPE”相反,但是当你想到它时,值的含义比类型更重要,类型只是对数据的编程约束
答案 2 :(得分:8)
如果变量的名称从第0列开始,则更容易找到变量的名称。
比较
QHash<QString, QPair<int, QString> > hash;
和
hash : QHash<QString, QPair<int, QString> >;
现在想象一下你的典型C ++标题的可读性有多大。
答案 3 :(得分:8)
增加的趋势是根本不说明类型,或者可选地说明类型。这可能是一个动态类型的语言,其中变量上确实没有类型,或者它可以是静态类型语言,从上下文中推断出类型。
如果有时会给出类型并且有时会推断出类型,那么如果后面有可选位,则更容易阅读。
还有一些趋势与语言是否认为自己来自C学校或功能学校或其他什么有关,但这些都是浪费时间。改善其前辈并且值得学习的语言是愿意接受来自所有不同学校的基于优点的输入的语言,而不是对特色遗产的挑剔。
答案 4 :(得分:6)
在形式语言理论和类型理论中,它几乎总是写成var: type
。例如,在类型化的lambda演算中,您将看到包含以下语句的证明:
x : A y : B
-------------
\x.y : A->B
我认为这不重要,但我认为有两个理由:一个是“x:A”是“x是A型”,另一个是类型就像一个集合(例如int
是整数集合,并且符号与“x∈A”相关。
这些东西中的一些早于您正在考虑的现代语言。
答案 5 :(得分:5)
“那些不记得过去的人被谴责重复过去。”
使用Fortran和Algol将变量前的类型开始无关紧要,但它在C中变得非常难看,其中一些类型修饰符在变量之前应用,其他类型之后应用。这就是为什么在C你有这样的美女
int (*p)[10];
或
void (*signal(int x, void (*f)(int)))(int)
与实用程序(cdecl)一起,其目的是解密这种乱码。
在Pascal中,类型位于变量之后,因此第一个示例变为
p: pointer to array[10] of int
与
对比q: array[10] of pointer to int
,在C中,是
int *q[10]
在C中,你需要使用括号将其与int(* p)[10]区分开来。 Pascal中不需要括号,只有订单才重要。
信号功能
signal: function(x: int, f: function(int) to void) to (function(int) to void)
仍然满口,但至少在人类理解的范围内。
公平地说,问题不在于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
所以,答案是:一个设计合理的编程语言将变量放在类型之前,因为结果对于人类来说更具可读性。
答案 6 :(得分:1)
这就是语言的设计方式。 Visual Basic一直都是这样。
大多数(如果不是全部)大括号语言都将该类型放在第一位。这对我来说更直观,因为相同的位置也指定了方法的返回类型。所以输入进入括号,输出超出方法名称的后面。
答案 7 :(得分:1)
我不确定,但我认为这与“名字与名词”概念有关。
基本上,如果你把类型放在第一位(例如“int varname”),你就会声明一个名为'varname'的整数“;也就是说,你给一个类型的实例一个名字。但是,如果先将名称放在首位,然后再输入类型(例如“varname:int”),则说“这是'varname';它是一个整数”。在第一种情况下,你给出一个名字的实例;在第二种情况下,你要定义一个名词并说明它是某个事物的实例。
如果你把桌子定义为一件家具,这有点像;说“这是家具,我把它称为'餐桌'”(类型第一)不同于说“桌子是一种家具”(最后一种类型)。
答案 8 :(得分:1)
我一直认为C的做法有点奇怪:用户必须隐式声明它们,而不是构造类型。它不仅仅是变量名之前/之后;通常,您可能需要在类型属性中嵌入变量名称(或者,在某些用法中,嵌入一个空格,如果您实际声明一个名称将)。
作为模式匹配的弱形式,它在某种程度上是可理解的,但它似乎也没有提供任何特定的优点。并且,尝试编写(或读取)函数指针类型可以轻松超越准备好的可懂度。总的来说,C的这个方面是一个缺点,我很高兴看到Go已经把它抛在了后面。
答案 9 :(得分:0)
首先放置类型有助于解析。例如,在C中,如果声明了像
这样的变量x int;
当您只解析x
时,您不知道x是声明还是表达式。相比之下,
int x;
解析int
时,您知道自己处于声明中(类型总是会启动某种声明)。
鉴于在解析语言方面取得了进展,这种微小的帮助现在并不是非常有用。
答案 10 :(得分:0)
Fortran将该类型放在第一位:
REAL*4 I,J,K
INTEGER*4 A,B,C
是的,对那些熟悉Fortran的人来说,有一个(非常虚弱的)笑话。
有空间可以说这比C更容易,当类型足够复杂时(例如,指向函数的指针),它会在类型周围放置类型信息。
答案 11 :(得分:-3)
动态(欢呼@wcoenen)类型语言怎么样?你只需使用变量。