您最常使用的编程语言最讨厌什么语法元素?[关闭]


27

无论您多么热爱一种编程语言,其中总是有一些细节并不尽如人意。

在这个问题上,我想特别关注语法元素。在您经常使用的一种编程语言(也许是您最喜欢的编程语言,或者您可能不得不在工作中使用的一种编程语言)中,您发现最不可读,不清楚,不便或不愉快的语法元素是什么?


@Nathan Taylor,不是针对这个问题,而是针对另一个问题
finnw 2010年

这个问题有修改吗?因为当我回答时,它并没有关注“语法元素” ...我现在必须修改我的答案。
Talvi Watia

@Talvi:不,它从一开始就是关于语法的。
Timwi's

@Timwi很奇怪,那一定是“回答一个问题,认为这是一个不同的问题”的情况。
Talvi Watia 2010年

如果您可以投票认为这是一个有用的问题,或者在下面有有用的答案,请投票。StackExchange网站需要投票才能建立一个良好的社区。您每天可以投票30张,不要浪费它们。特别是享有较高声誉和低票数的用户,请阅读以下内容:meta.programmers.stackexchange.com/questions/393/…–
Maniero

Answers:


39

JavaScript中的分号插入。

我并没有经常被它咬伤,但是这是一个非常糟糕的主意,它使我旋转。


这是规则(来自ECMA-262第7.9节)

  1. 当程序包含形式语法不允许的标记时,如果(a)此处有换行符,或(b)意外标记是右括号,则插入分号。
  2. 到达文件末尾时,如果无法解析该程序,则插入分号。
  3. 当遇到“受限生产”并且在语法包含注释“ [此处没有LineTerminator]”的位置包含行终止符时,则会插入分号。

例:

return 1; // returns 1

return
1; // returns undefined

2
JavaScript:世界上最
容易被

是的,许多人期望JavaScript是一种“自由格式的语言”,但事实并非如此。
Andreas Rejbrand

13
一旦意识到JavaScript是为创建HTML而设计的,这就有道理,当在语法上无效时,它试图解释您的代码“真正意味着”的历史由来已久。(有时要查看“鲁棒性原则”,这是计算机历史上最大的灾难。)
Mason Wheeler 2010年

7
对我来说,这些类型的错误是代码臭味,程序员是草率的,并且从未使用过大多数形式化的“严格”语言,这些语言通常会因省略分号而导致语法错误。
Talvi Watia

7
Wohoo,最后其他人也认为稳健性原则是一场灾难,使HTML变得一团糟。
罗曼·斯塔科夫

39

由于缺少C#属性,因此使用Java Bean语法

/**
 * Name of user
 */
private String name;

/**
 * Gets name of user
 * @return Name of user
 */
public String getName() {
    return this.name;
}

/**
 * Sets name of user. 
 * @param name
 */
public void setName(final String name) {
    this.name = name;
}

啊!

我有这个问题

  • 太多代码 -有一个已记录的字段,一个已记录的getter方法和一个已记录的setter方法。这个极其基本的示例针对单个属性包含20行代码
  • 杂波方法列表 - “让我找到方法,一方面于:getXgetYgetZgetAnotherAnnoyingFieldgetWhyIHateJavaBeansgetThisIsVerbosegetGAH...有啊这是,hashCode
  • 多个区域的文档导致糟糕,过时或丢失的文档 -试图理解什么代码时很烦
  • 如此恼人第三方不得不拿出一个插件可以轻松地做到这一点 - 鲨鱼,等等。

9
再次,当代码过于冗长以至于需要自动生成工具时,出了点问题。我是NetBeans,但它也具有自动生成getter和setter的功能。但是Javadoc脱离了syn,它仍然很冗长,它仍然使javadoc
混乱

11
如果您需要使用getter进行所有操作,则客户端代码有问题。
finnw

7
使用getter和setter方法会破坏封装。该字段也可能public。成员应该是私有的,并且应该由具有更高层次逻辑的类明智地操纵,而不是使用客户端代码中的getter和setter方法。
greyfade

6
@greyfade:如果是公开的,则不能轻易更改设置代码的作用(您必须从外部更改用于设置字段的所有代码)。
Bart van Heukelom

3
@SHiNKiROU:Java看起来干净吗?我以前从未听说过!我对Java的主要抱怨是,看似简单的事情需要花几十行代码,而我需要从心理上忽略它们。
configurator

33

空格灵敏度。

Python在这方面惹恼了我。我的意思是,无论如何我都会缩进,但这使我不得不这么做。使表示形式成为语法的一部分让我感到不快。


8
您将学会爱上它
user10008 2011年

2
语法演示文稿
Winston Ewert 2012年

32

switch声明(在C,C ++,C#,Java等)

这是为什么我觉得很不方便的示例:

switch (someVariable)
{
    case 1:
        int i = something();
        doSomething(i);
        break;

    case 2:
        int i = somethingElse();
        doSomethingElse(i);
        break;
}

这不会编译,因为i在同一作用域中重新声明了变量。这似乎是一个很小的细节,但它确实经常咬我。我可以添加大括号来缓解这种情况,但是如果大括号是语法的必需部分,并且没有多余的缩进级别,那会很好。我也真的很讨厌不得不写多余的东西break。这样会更好:

switch (someVariable)
case 1
{
    int i = something();
    doSomething(i);
}
case 2
{
    int i = somethingElse();
    doSomethingElse(i);
}
default
{
    ...
}

这使它看起来更像if/ else链,这是一件好事,因为它在语义上也相似。至少在C#中,它仍然不是同一回事,因为在一条switch语句中,大小写标签的顺序无关紧要,而在if/中else却是如此。


1
不幸的是,您改进的语法消除了大多数这些语言中switch的最大功能:穿透。C语言中的“达夫设备”是这种特殊“错误功能”价值的完美示例。在类似C的语言中,在解释器和类似程序中使用穿透也是很常见的。
greyfade

7
不,它并不能消除它。goto就像C#中一样,它仅要求将其更明确(使用a 或类似名称)。
Timwi's

8
@greyfade:任何在C语言中使用duff的设备的代码都必须丧命。编译器会比您做出更好的决策。
Billy ONeal

4
@greyfade:在以下情况下,Delphi通过简单地允许多个索引来解决多值问题case Foo of 1,3: Result := 'odd'; 2,4: Result := 'even' end;
Frank Shearar 2010年

3
@jkerian:现在想象一下它break是默认值,只需要指定fallthrough 。无需记住评论了!:)
Timwi

27

VB.NET中的数组声明

我总是忘了,在VB.NET中初始化固定数组时,您是在指定数组的上限,而不是在C / C ++,PHP或Java中指定元素的数量。除了VB6(我们不会去那里...),我想不出另一种这样做的语言:

Dim myArray(20) as Integer  '# Creates an array with 21 elements,
                            '# indexed from 0 to 20

我认为所有BASIC语言都可以做到这一点...我知道原始BASIC和QBasic都可以做到。
Michael K

OMG真是可怕。...+1
mikera 2011年

25

VB6-单独的变量声明和赋值

大多数语言都允许您声明一个变量并将其分配给一行代码。另一方面,VB6迫使您使用两个。

Dim i as Integer
i = 0

Dim derpderp as Collection
Set derpderp = new Collection

您可以使用冒号将两个命令放在一行上,但是在实际代码中它很快就会变得混乱。

Dim i as Integer: i = 0
Dim derpderp as Collection: Set derpderp = new Collection

7
+1,因为必须使用VB6作为您最常用的语言。
Walter 2010年

9
我每天都用它。
systempuntoout 2010年

Pascal是否有类似的语法?我一直认为这很讨厌。
greyfade

1
有一个特殊情况:如果您Dim Hurp As New Collection访问Hurp时引用了Nothing,则将在访问之前对其进行神奇的初始化。如果您明确将其设置为Nothing并再次触摸它,它将复活...喘着粗气!
杰弗里·汉汀

1
+1百万为Derp。Derp de derp de tiddly tum de derp。
MVCylon

24

用CSS注释

//不会像其他许多语言(如PHP和Javascript)那样注释掉代码行。虽然/* this is commented out */有效,但我更喜欢使用//

这很麻烦,因为有一半时间我忘记了编辑CSS,然后不得不返回并修复错误。


在当今的时代,您会认为原始CSS将被视为目标代码。
Tom Hawtin-大头钉

//可以很好地注释掉CSS。我一直都这样做。我真正要做的就是输入垃圾。但这似乎可以跳过不可解析的行。
MVCylon 2011年

1
@MVCylon如果使用//注释掉一行,则该行之后的任何内容也会被跳过。{在该特定样式内}换句话说,它会失败,因为不应跳过这些行。
Talvi Watia

20

PHP-参数的一致顺序

PHP具有许多方便的函数,它们几乎可以对数组或字符串进行所有操作。其中许多操作都需要同时使用a $needle和a $haystack,但是不同的函数将它们以不同的顺序进行处理。哪个功能需要哪个参数是我的大脑拒绝吸收的那些事实之一,无论我遇到它们有多频繁!

使用in_arraystrstr函数:

// Check whether $needle occurs in array $haystack
bool in_array (mixed $needle, array $haystack [, bool $strict])

// Check whether $needle is a substring of $haystack
string strstr (string $haystack, mixed $needle [, bool $before_needle=false])

有趣的是,PHP似乎在内部与这些顺序保持一致,因为所有字符串函数似乎都在使用,$haystack, $needle而数组函数则相反,但是对于刚接触PHP的人来说,这可能需要一些时间。在ExpressionEngine上有一篇很好的文章,更详细地讨论了这个特殊的问题,并且在PHP bug列表中进行讨论,其中PHP团队的回复很短!

helly@php.net
然后使用一个不错的IDE。

2
记住顺序比较容易$needle$haystack因为它使人联想起在大海捞针中找针的方式。
kiamlaluno'9

3
提示:在数组功能中,针是第一位的。在字符串函数中,haystack首先出现。
GSto

17
我喜欢这个名字strstr。如此精美,毫无意义。
configurator

5
只需阅读PHP的bugtracker中的链接条目即可。说真的,wtf?对于任何API来说,Imho一致性都是一个有效的问题,仅以“然后使用一个不错的IDE”作为响应只是一个无效的答复。至少它可以被开发者说成不那么具有煽动性。
Baelnorn

2
老实说,让我为此感到疯狂的是,它根本不应该是一个功能!它应该只是一个方法:$ haystack-> find($ needle)。木已成舟。
riwalk

19

蟒蛇

self 实例方法定义中的参数


在类方法中,通常将其命名为cls,并且使用self违反约定。

如果您考虑一下,这实际上是有道理的。与在其他语言中声明私有方法相同,self参数在python中只是显式的,而在其他语言中则是隐式的。如果要使其隐式,请在方法声明之前添加@classmethod装饰器。请参阅docs.python.org/library/functions.html#classmethod。了解有关其工作原理的详细信息将使您对隐式使用其他语言的工作方式有所了解。
Evan Plaice 2010年

4
我了解原因以及为什么将其保留在那里neopythonic.blogspot.com/2008/10/…但我仍然不喜欢它
GoranPeroš10年

@Evan Plaice:“ self参数只是在python中是显式的,而在其他语言中则是隐式的”,这只是故事的一部分。另一部分是每周输入的python。在一起很可怕,忘记self很容易发生,并且要花费时间。
maaartinus 2011年

@maaartinus然后将类方法装饰器添加到您的实例方法。与“弱类型”无关。它只是使静态方法/函数(无“ self”参数)与实例方法(包括“ self”)之间的关系显而易见。除非您提供实例方法的引用,否则实例方法不知道它的父类。在其他语言中,我概述的区别特征只是隐藏在语法糖后面。如果可以选择全部完成,那么我将首先开始使用Python学习OOP。
Evan Plaice 2012年

18

爪哇

期。句号 故事结局。

从哪儿开始?哦,我知道从哪里开始:Java异常复杂,丑陋,愚蠢且固有损坏的泛型。需要我多说?:(好的,然后:键入erasure

然后是不确定的资源管理。脚船夫!

接下来是什么?哦,是的:Java的愚蠢正则表达式是我最讨厌的东西。我无法计算由于没有足够的反斜线而被抽水的次数。这比无法访问本千年以来的任何Unicode属性要糟糕得多,这是完全事实。 十年过时了!!!完全没用。乱扔垃圾

然后是字符类快捷方式不适用于非ASCII的错误。多么皇家的痛苦!并且甚至不要考虑使用\p{javaWhiteSpace}; 它对几个非常常见的Unicode空白代码点没有做正确的事情。

你知道\p{javaJavaIdentifierStart}有财产吗?他们在想什么呢?很高兴他们对如此狡猾的偷窥者感到不满。

曾经尝试使用CANON_EQ标志吗?您知道那确实有什么作用吗?所谓的“ Unicode大小写”怎么样?一堆普通的包装盒根本无法使用。

然后,它们使编写可维护的正则表达式变得很困难。Java仍然没有弄清楚如何编写多行字符串,因此您最终会写出如下疯狂的东西:

    "(?= ^ [A-Z] [A-Za-z0-9\\-] + $)      \n"
  + "(?! ^ .*                             \n"
  + "    (?: ^     \\d+      $            \n"
  + "      | ^ [A-Z] - [A-Z] $            \n"
  + "      | Invitrogen                   \n"
  + "      | Clontech                     \n"
  + "      | L-L-X-X                      \n"
  + "      | Sarstedt                     \n"
  + "      | Roche                        \n"
  + "      | Beckman                      \n"
  + "      | Bayer                        \n"
  + "    )      # end alternatives        \n"
  + ")          # end negated lookahead   \n" 

这些换行符是什么?哦,只是Java的愚蠢。他们使用Perl注释,而不是Java注释(白痴!),直到行尾。因此,如果您不把那些放在\n那儿,那么就砍掉其余的模式。and和双du!

不要在Java中使用正则表达式:您最终只会想砸东西,这一切都是那么痛苦和破裂。我不敢相信人们会忍受这一点。 有些不

然后,我们可以开始讨论编码带来的Java白痴废话。首先,事实是,即使Java的字符是Unicode,默认的平台编码始终是一些la脚的8位编码。然后就是他们如何在编码错误时不引发异常。您一定会胡扯。还是这样:

OutputStreamWriter(OutputStream out) 
          Creates an OutputStreamWriter that uses the default character encoding.
OutputStreamWriter(OutputStream out, Charset cs) 
          Creates an OutputStreamWriter that uses the given charset.
OutputStreamWriter(OutputStream out, CharsetEncoder enc) 
          Creates an OutputStreamWriter that uses the given charset encoder.
OutputStreamWriter(OutputStream out, String charsetName) 
          Creates an OutputStreamWriter that uses the named charset.

有什么不同?您是否知道,如果遇到编码错误,只有其中一个会引发异常?剩下的只是给他们开枪。

然后是Java字符的独特之处还不足以容纳字符!他们到底在想什么?这就是为什么我称它们为charchars。如果您希望它能正常工作,则必须编写如下代码:

private static void say_physical(String s) { 
    System.out.print("U+");
    for (int i = 0; i < s.length(); i++) {
        System.out.printf("%X", s.codePointAt(i));
        if (s.codePointAt(i) > Character.MAX_VALUE) { i++; }  // UG!
        if (i+1 < s.length()) { System.out.printf("."); }
    }
}

还有谁想这样做?旁边没人。

有多少个字符"\uD83D\uDCA9"?一个或两个?取决于您如何计算它们。正则表达式引擎当然会处理逻辑字符,因此模式^.$将成功而模式^..$将失败。这种疯狂表现在这里:

String { U+61, "\u0061", "a" }  =~ /^.$/ => matched.
String { U+61, "\u0061", "a" }  =~ /^..$/ => failed.
String { U+61.61, "\u0061\u0061", "aa" }  =~ /^.$/ => failed.
String { U+61.61, "\u0061\u0061", "aa" }  =~ /^..$/ => matched.
String { U+DF, "\u00DF", "ß" }  =~ /^.$/ => matched.
String { U+DF, "\u00DF", "ß" }  =~ /^..$/ => failed.
String { U+DF.DF, "\u00DF\u00DF", "ßß" }  =~ /^.$/ => failed.
String { U+DF.DF, "\u00DF\u00DF", "ßß" }  =~ /^..$/ => matched.
String { U+3C3, "\u03C3", "σ" }  =~ /^.$/ => matched.
String { U+3C3, "\u03C3", "σ" }  =~ /^..$/ => failed.
String { U+3C3.3C3, "\u03C3\u03C3", "σσ" }  =~ /^.$/ => failed.
String { U+3C3.3C3, "\u03C3\u03C3", "σσ" }  =~ /^..$/ => matched.
String { U+1F4A9, "\uD83D\uDCA9", "💩" }  =~ /^.$/ => matched.
String { U+1F4A9, "\uD83D\uDCA9", "💩" }  =~ /^..$/ => failed.
String { U+1F4A9.1F4A9, "\uD83D\uDCA9\uD83D\uDCA9", "💩💩" }  =~ /^.$/ => failed.
String { U+1F4A9.1F4A9, "\uD83D\uDCA9\uD83D\uDCA9", "💩💩" }  =~ /^..$/ => matched.

这种愚蠢的想法是因为您无法写出完全合理的\u1F4A9文字,当然也不会收到任何警告,说明您无法做到这一点。它只是做错了事。

笨蛋

当我们这样做时,整个\uXXXX记号先天性地死了。Java预处理程序(是的,您听说过)比Java更早实现了,所以您被禁止编写诸如之类的完全合理的东西"\u0022",因为当Java看到时,它的预处理程序已将它变成""",因此您会迷失方向。哦,等等,,如果它在一个正则表达式!这样就可以使用"\\u0022"了。

权利!

您知道Java中无法isatty(0)拨打电话吗?您甚至都不被允许考虑这种想法。这对您不利。

然后是整个类路径可憎。

还是事实是无法在同一源文件中指定Java源文件的编码,这样就不会丢失它?我再次想知道:他们在想什么?

停止疯狂!我不敢相信人们会忍受这种垃圾。这是一个完全的笑话。我宁愿成为沃尔玛的问候者,也不愿忍受残酷的Java精神错乱所带来的麻烦。一切都坏了,他们不仅无法修复,而且无法修复。

这是同样的狡猾,贪婪的人,他们以一种使某项printf()功能非法的语言感到自豪。e,肯定效果很好,不是吗??

纯粹的麻木头骨。them子拍对他们来说太客气了。如果我想用汇编器编程,我会的。这不是一种可挽救的语言。皇帝没有衣服。

我们讨厌它。我们永远讨厌它。让它死死


哈哈,好人,我不碰Java,因为它像您描述的那样过于粗糙。至于\ uD83D ...好吧,我想有一种更好的说法是,您宁愿字符串不是UTF-16,而是UTF-32。如果您接受UTF-16-ness,则正则表达式会做正确的事;这是.length的电话。
罗曼·斯塔科夫

4
-1。除了regexp注释和Unicode转义,您提到的其中一项都不是语法元素。
约尔格W¯¯米塔格

3
@Jörg,您要语法吗?好的,可以:Java允许您在标识符中放入控制字符,包括ESC和NUL。他们在想什么???
tchrist

4
@tchrist:哇!如果我再次编写Java程序,我所有的变量的名称将由不同数量的退格字符(^H)组成:)
j_random_hacker 2010年

1
@tchrist,现在感觉好些了吗?

16

C和C ++中的函数指针声明语法:

(int)(*f)(int, int);

声明一个名为f的函数指针,该指针的指针可以为2 int并返回int

我更喜欢这样的语法:

f: (int, int) => int

假设您要声明一个函数指针g,该指针的pointe可以接受两个ints,并且函数from intintto 可以取一个int,然后返回int

使用C或C ++表示法,您可以将其声明为:

(int)(*g)(int, int, int(int, int));

使用上述提议的符号,可以将同一事物声明为:

g: (int, int, (int, int) => int) => int

后者是更直观的IMO。


另外:称为OOC的编程语言可修复此语法(以及C和C ++中的其他各种语法问题)。在此处查看其主页。


同意,某些“普通C” /“ C ++”不支持它,或不支持其他语法。特殊语法有助于指示何时支持编程语言功能。这就是C#添加“委托”语法的原因。
umlcat 2011年

代表们不仅语法糖,因为它们也将对象存储(与C ++成员函数指针,具有比普通的函数指针语法更糟)
陶Szelei

14

Java的详细程度。

即:

public static final int 

6
相比?(15个字符)
TheLQ 2010年

7
相比:const int例如。
OscarRyz

11
“公共静态最终int x = 4;” 与Haskell中的“ x = 4”相比。
Jared Updike 2010年

24
那不是冗长。尝试a+(b*c)/d*e+f/g^20使用BigIntegerJava 编写。为什么这种语言不允许运算符重载?
MAK 2010年

4
@Michael:需要为此付出保护的程序员可以通过完全不编写:D来最好地保护自己(并减轻其他人的痛苦)。
MAK

12

PHP中的\ we \ wouldnt \ fix \ our \ parser命名空间语法

该语法不仅丑陋,而且在新开发人员必须考虑字符串中的名称空间时会引起混乱。(PHP在双引号字符串中插入反斜杠作为转义序列。试图以\you\should\never\do\that双引号字符串而不是单引号字符串表示名称空间将导致换行,制表符和灾难。)


是的,有人想到了一种更好的::方法,但是PHP坚持要求每个运算符都必须不同。我对这里的滥用问题感到好奇。
艾伦·皮尔斯

同意。PHP需要名称空间,但是语法使它搞砸了
umlcat 2011年

9

我鄙视以下事实:在if / while / for语句之后,花括号可以是可选的。

特别是当我看到类似的代码时,

if (...)
    for(...)
        ... One line of stuff ...

请放入括号并完成操作。


6
嗯..这取决于。对于仅检查条件并返回错误代码(或引发异常)的“异常终止”,我宁愿看不到括号。
Billy ONeal

4
如果您将自己限制在极端多层次的情况下,我会同意的,但是您的发言太笼统了。对于简单的单语句if和循环,具有简短形式的功能非常有用。
Timwi's

2
我的规则:仅当一条语句需要多个子语句或包含这样的语句时,才应将其用大括号括起来。因此for (...) while (...) if (...) { x(); y(); },最好将其重写为for (...) { while (...) { if (...) { x(); y(); } } }带有适当缩进的。
乔恩·普迪

6
我恰恰相反-我鄙视那些坚持在不必要的时候大括号的人。只是学习编程。
杰里·科芬

3
我真的很喜欢括号,即使在单个if语句中也是如此。它使我可以更好地遵循程序的流程。
里卡多·桑托斯

9

VBScript没有逻辑运算符

与几乎每种明智的语言不同,VBScript使用按位运算符而不是逻辑运算符。实际上这是什么意思?好吧,正如埃里克·利珀特Eric Lippert)指出的那样

If Blah = True Then Print "True!" Else Print "False!"

If Blah Then Print "True!" Else Print "False!"

在VBScript中不一样!

但是,更糟糕的是,这意味着VBScript中没有短路评估,因此,如果以下语句将使您的程序崩溃BlahNothing

If (Not Blah Is Nothing) And (Blah.Frob = 123) Then
...

没错,即使第一个错误,VBScript也会评估AND比较的两个部分!只是让它陷入...


3
直到您发现an内的错误If x Then ... If Not x Then ... End If ... End If并发现x为2的那一天,您才真正使用VB / VBScript进行编程。
configurator

7

编辑:在评论中的讨论之后,我决定更新此答案以更好地解释自己。

我真的很讨厌函数指针在C中的显示方式。通常,任何变量声明都看起来像一个元组:type varname; 另一方面,函数指针声明看起来像是函数名称之前带有*的函数声明。我可以接受它作为指针类型的描述,但是在C语言中,它同时声明了类型和该类型的变量的名称。在我看来,这是不一致的,因为类型声明与变量声明是不同的。struct myStruct{int X; int Y;}仅定义类型,未定义名为的变量myStruct。同样,我没有看到将类型声明和变量声明分组到函数指针中的一个原子语句中的理由,也看不到与type varname;结构的偏差。

有人指出这与某些螺旋规则是一致的,也许是这种情况,但是好的语法的标志是它具有自我解释性,并且其内部逻辑是显而易见的。螺旋定律无论如何都不是显而易见的。


1
它与该语言的其余部分一致,所以也许您的抱怨是关于C声明符的语法?您喜欢Go中使用的语法吗?
finnw

用什么方式一致?通常会这样:输入varname;。当我们创建一个新的复合类型(如struct)时,首先是声明(可能带有typedef),然后创建该类型的变量。当我们声明一个函数指针时,它是int(* foo)(int arg1,int arg2),然后用作传递给函数的参数类型:void newFoo(int(* foo)(int arg1,int art2 ))....并作为变量:foo = a_compatible_func; 我认为首先是函数声明,然后是var声明会更加一致,例如:typedef int(* foo)(int,int)MyFoo; MyFoo myfoo;
EpsilonVector 2010年

这就是为什么你得到typedef
zneak 2010年

4
@EpsilonVector:我倾向于同意函数指针语法很讨厌,但是遵循一个简单的规则可以使它更易于阅读。顺时针旋转规则(也许您已经看过?):c-faq.com/decl/spiral.anderson.html
greyfade 2010年

1
EpsilonVector:我不确定您希望从指针变量声明中声明除变量名以外的其他内容。

6

VBScript中的分号-或缺少分号

我整天都在用期望在每行结尾使用分号的语言进行工作。在VBScript行的末尾添加一个,您的代码将不再运行。


4
支持这一点,不是因为我特别喜欢分号,而是因为我真的很讨厌 VB 通过使换行符变得如此不便而鼓励长行的方式。
Shog9

6

输入/输出参数。我全力支持论证(我是好东西),论证也很好,但是必须传达这两种状态的论点惹恼了我。

我这里的目标是从参数获取输入,然后用某些输出覆盖该输入的函数。可以通过引用传递对象来更新它。但是,大多数情况下,对于原始类型,获取一个对象,使用它,然后完全更改它,对我来说是不合适的。您不应该通过inout 更改参数的含义


你想用什么语言?如果使用C#,那么我会不同意它的烦人之处,因为它总是显式的(不同于C ++。)而且我也不知道任何主流语言会迫使您将参数声明为in / out。
finnw

@finnw我从来没有见过,你一个语言不得不inin论点要么,我只是在谈论它们。而且,在我看来,没有什么可以原谅输入/输出参数,而将其明确表示并不能减轻痛苦。应该没有理由必须使用对函数有帮助的值来初始化局部变量,并具有相同的变量,然后突然包含函数决定放入的任何内容。这两个应该是不同的。总是。
zneak 2010年

抱歉,我当时不太清楚。我的意思是说“我不知道所有参数都隐含在+ out中的任何语言”,即您没有被迫使用该功能,但是有合法的用例(例如,更新struct新值取决于值的情况)相同的另一个字段struct。)
finnw 2010年

@finnw通过引用传递的对象(例如classC#中的对象实例)由函数修改,对我来说很好。除了我不喜欢非常数结构之外,还可以通过传递struct带有ref关键字的a来更新它。我真正讨厌的是输入被输出覆盖。我能想到的最好的例子是Berkeley socket的accept函数:它需要一个socklen_t*参数,在输入时必须包含struct sockaddr*所传递的大小;并且在输出时,将包含已写入其中的字节数。这应该是犯罪的。
zneak 2010年

我同意这很不好(IIRC某些Win32 I / O函数的作用相同),但这是对功能的滥用(函数调用更改了传入变量的含义,而不仅仅是其值),并不意味着该功能本身是不好的。
finnw 2010年

6

C和C ++中的数组声明。

通常,变量声明的格式为type variable_name。您可以轻松地从左到右读取这些声明。但是int foo[size]首先看起来像是声明foo为int,然后进一步阅读,发现foo的类型为“整数数组”。 int[size] foo读起来好多了。

而且我也很讨厌它,当程序员声明这样的指针类似的原因:int *foo。由于某些原因,我没有弄清楚,这是它编写的典型方式。


1
重新指针声明:之所以这样写是因为' '绑定到变量名,而不是类型。因此,int* a, b;值不一定申报ab为指针; 唯一的a是。因此,最好将其编写为int *a, b;(甚至最好将它们编写为两个声明)。
史蒂夫·梅尔尼科夫

好点子。太糟糕了*,没有绑定到类型。
雅各布

2
这更不用说函数指针了…… void(int) *f;?不:void (*f)(int);
注意:想起一个名字,2010年

在现代C ++中,几乎不需要指针和数组。
fredoverflow

2
@Steve Melnikoff:尽管我对该答案+1了,但我认为int* a, b;您提到的问题更为严重。
j_random_hacker 2010年

5

Java中的冗余参数化:

HashMap<String,HashMap<String,String>> foo = new HashMap<String, HashMap<String, String>>();

编译器认为 foo还有什么其他类型的参数化?


4
我希望您知道Java的(有限)类型推断吗? HashMap<String,HashMap<String,String>> foo = Maps.newHashMap();
finnw

1
Java 7:HashMap<String,HashMap<String,String>> foo = new HashMap<>();
Bart van Heukelom

5
好吧,它可以具有所需的任何类型,无论如何这些类型都将被删除...
configurator

缺乏类型推断,是什么意思?
missingfaktor

What other type parameterization does the compiler think foo could have?-无论出于何种原因,它都是原始类型-好像任何理智的人甚至会混合使用原始类型和参数化类型。
maaartinus 2011年

5

由于人们已经对=vs 提出了抱怨==,让我指出一个更糟糕的选择。PL / I同时拥有:==但是当某项“显然”是一项任务时,它将让您摆脱使用=它的麻烦。:=在编译器将其解释为比较的情况下,使用let可以强制将某些内容作为赋值。

不幸的是,编译器并非总是以您期望的方式做出决定。仅考虑一个明显的例子:

A = B = 0;

现在,对于大多数熟悉大多数“普通”语言的人来说,这的含义非常明显-为A和B都分配0。PL/I只是有点...不同。由于只有(疯狂的)语言设计者才知道的原因,第一个=解释为赋值,而第二个=解释为比较。因此,这会将B比较为0,然后将该比较结果分配给A(遵循C样式约定,即“ false”导致0,“ true”导致1)。

因此,如果B为0,则A变为1。否则,A变为0。换句话说,这实际上不是在给A和B分配相同的值,而是确保A 不能具有与B相同的值。

底线:尽管起初C / C ++ / PHP风格看起来很痛苦,但替代方案要糟糕得多1

1好吧,从技术上讲,还有另一种选择:Pascal样式,=始终表示比较和赋值总是需要的:=。使用一段时间后,很明显(至少对我而言),分配比比较要普遍得多,如果您需要额外的“材料”来消除二者的歧义,则一定要保持分配的简洁明了,比较时需要额外的“垃圾”,反之亦然。


1
我什至建议将其==用于平等和:=分配。这样,您可以输入更多信息,但是避免孤独=有助于避免错误。
maaartinus 2011年

@maartinus:至少对我来说,这听起来绝对是最糟糕的可能性,但这就是生活……
Jerry Coffin

3

佩尔

  1. 我希望Perl让我写信if($x < 10) do_something();。目前,您必须将其写为do_something() if($x < 10);if($x < 10) { do_something(); }

9
do_something() if ($x < 10);还不错
zneak 2010年

并非如此,并且在许多情况下比if(..) ...启动更干净,因为您可以使所有表达式在右边对齐。但是有时候我真的很想说if($x < 10) do_something();,不幸的是Perl不允许我这样做。
Gaurav

7
不幸的是,直到您写完if ($x<10) do_something(); and_call_me(); 然后又想知道为什么从未接到电话。我希望C和家人需要使用大括号以防止发生此类错误。
AShelly

2
@AShelly:或者实际上为什么总是打个电话。
zneak

1
@zneak除了没有else。(我希望它EXPR1 if COND else EXPR2像Python一样)
Ming-Tang

3

reinterpret_cast<unsigned long>在C ++中。此操作对于处理外部API并确保数值精度很有用,为什么键入起来这么麻烦却看起来那么麻烦?


17
提醒您,您应该努力编写不需要的代码,这很丑陋。:)
greyfade

对我来说,这是一种很好的理论计算机科学论据,但以我的经验来说,避免它太有用了(但是,我的许多经验是普通的旧C语言,因此我可能会有偏见)。
AShelly

5
这并不是一个理论上的CS参数:reinterpret_cast在C ++中使用a 是很强烈的代码味道。99%的时间,当您要使用它时,您很有可能不需要-您可能做错了什么。其他1%的时间是您与C进行接口。reinterpret_cast如果不能,它将破坏类型系统以使其正常工作。这通常是一件坏事。
greyfade

3

遍历数组时,JavaScript中的for ... in构造和PHP中的foreach构造。与正确的代码相比,它们使编写错误更容易。


3
哇,真是胡扯。“比正确的代码”。走开。
乔纳森·斯特林

如果我不得不编写额外的代码以安全地使用它们,那么在我的书中它们更容易被错误使用。for ... in需要额外的检查,以确保您没有遍历原型中的对象,而foreach则需要您随后清理引用,否则可能会覆盖数组中的最后一个值。
Joeri Sebrechts 2010年

更改引用(&运算符)的foreach是一个著名的错误...
umlcat 2011年

1
我很困惑,我以为JavaScript中的“ for..in”构造坏了是常识……为什么这种冒犯性?
lvilnis'1

2

C / C ++中的数组或数组的指针。我仍然对这些感到困惑。


3
向后读取类型。int[]*是一个指向整数int*[]数组的指针,并且是一个指向整数指针的数组。同样适用于consts:int* const是整数的常量指针,而const int*and int const*是指向整数(或整数常量)的指针。
zneak

@zneak:“从右到左”不起作用,请参阅提到的“顺时针螺旋” /“由内而外”规则。

或者,只需使用typedefs,就不会造成混乱。
Billy ONeal

在现代C ++中,几乎不需要指针和数组。
fredoverflow

4
@tchrist:不对。int (*p)[10];声明p是一个指向10个整数的数组的指针。如果sizeof (int) == 4,然后p++将提前p通过40
j_random_hacker


1

Javascript / Java等,等于比较,例如if(a == 1)

我应该写几次if(a = 1)?

作为一个人,我读得很完美。但是织补解释器/编译器说:“嘿,我给a赋值1,然后检查a是否等于1,您是否相信它是对的!

把我逼上墙。

if(a == 1)的可读性要差得多,无论如何解释器/编译器应该知道我的意思;数百年来,许多其他次要语言(VB)一直在成功地进行开发。


是什么if (a = true)意思?
Tom Hawtin-大头钉

2
分配只是不应该返回值。它有时很有用,但在大多数情况下,这只是脖子上的疼痛。
configurator

在Javascript中,JSLint会为您抓住这一点。
Zachary K

问题是,条件分配可能很有用。我发现<tt> while(element = list-> next())</ tt>很清晰。因此,我不确定是否要删除它。
印加

3
@Tom:这意味着您不了解布尔值。如果您的意思是if (a == true),只写if (a)。如果您的意思是a = true,那么该if语句是多余的。
dan04 2011年


0

structPointer->member在C / C ++中。可能适合阅读别人的代码,但我不喜欢它。两个字符而不是一个...太浪费空间了!


2
不幸的是,必须与区别.,后者适用于非指针对象的成员。模棱两可的语法不好,mmmkay?
greyfade

2
@greyfade:是的!因为编译器不可能使用其类型系统规则来告诉您何时使用结构指针类型并隐式地应用取消引用。不,那是个疯狂的话题!(但是,即使您弄错了它,它仍然可以通过某种方式给您一条错误消息。)语法没有任何歧义。像往常一样,这只是C令人头疼。如果您实际上是在需要指针指向记录的黑暗角落中工作,Delphi确实可以进行隐式取消引用,因此可以在不混淆解析器的情况下完成此操作……
Mason Wheeler

5
@Mason:像的情况如何shared_ptr,其中->访问所包含的类型并.访问其shared_ptr自身的属性?抱歉,我在这里完全不同意。
Billy ONeal

2
可能更糟。可能是PHP,您必须在其中使用->来访问任何对象
卡森·迈尔斯,2010年

1
@maaartinus:任何严重依赖于非显而易见的操作顺序的代码都不是我将要编写的代码。
Billy ONeal

0

括号中的Scala多行代码

例如:

class Foo(
         val bar: String,
         val baz: Int,
         val bing: String,
         val bong: Boolean
 ) extends Model {
   // body here
 }

您实际上从中得到的是很棒的。它为您生成构造函数以及getter和setter。但是它确实很丑陋,打破了我所有关于如何缩进代码的思维模式,并且基本上让我感到自己像是在一个怪异的三明治中,一方面是Java,另一方面是Lisp。(哦,等等……这就是Scala的重点。)


我很困惑-您是指括号中的部分(val bar依此类推)还是花括号中的部分(紧随其后的部分extends Model)?(该代码中没有方括号)
Billy ONeal

3
括号中的部分。我是英国人。我们将其称为方括号,因为在这种情况下,它们没有起到括号的作用。
汤姆·莫里斯

2
如果以这种方式缩进,看起来还不是很糟糕:pastebin.com/h9qC8XGg
missingfaktor 2010年

我发现水平地写这些构造函数参数列表更容易阅读,尤其是当我只有几个参数时。
MJP

在我看来是一种方法。就像Simula。好老学校。
汤姆·霍顿
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.