哪些语言功能被认为有害?[关闭]


20

说明原因,并列出实现了(mis)功能的语言。

发布您认为有害的功能,而不是您不喜欢的功能。



2
@sbi您也可以在同一页面上阅读“ XMLHttpRequest被认为有害” ...
HoLyVieR 2010年

1
除基本表达外,所有这些都被认为对某些人有害。
David Thornley,2010年


3
@David Thornley:a = 1/0-基本表达,有害。;-)
2010年

Answers:


37

在PHP中注册Globals

信息:http : //php.net/manual/zh/security.globals.php

出于可读性和安全性考虑,这是迄今为止最糟糕的功能。基本上所有收到的GET参数都转换为变量。

例如,使用以下URL:/index.php?value=foobar

您可以执行以下操作:

<?php
echo $value; // return foobar
?>

当您阅读代码时,知道变量的来源非常令人困惑。

另外,如果滥用该功能,可能会导致安全漏洞。这是来自php.net的代码示例,展示了如何滥用它:

<?php
// define $authorized = true only if user is authenticated
if (authenticated_user()) {
    $authorized = true;
}

// Because we didn't first initialize $authorized as false, this might be
// defined through register_globals, like from GET auth.php?authorized=1
// So, anyone can be seen as authenticated!
if ($authorized) {
    include "/highly/sensitive/data.php";
}
?>

那太糟了。虽然我可以理解需求,但默认情况下保持需求毫无意义
TheLQ

14
应当指出并强调的是,自PHP 4.2(一直追溯到2000年)以来,默认情况下未启用寄存器全局变量,在PHP 5.3(2009年)中已弃用该寄存器全局变量,并且在PHP 6中将其完全删除,但人们仍然会回头甚至在10年后仍然可以很好地进入“ OMG全球注册”。

1
绝望的PHP
Ming-Tang

@SHiNKiROU这不是绝望,这功能被取消,并将在PHP 6中移除
HoLyVieR

1
这并非没有希望,它与许多其他语言相距遥远,以至于任何人使用它的唯一原因是因为直到最近,它比其他语言更容易获得便宜的虚拟主机。
直觉

22

默认情况下允许Null,即“万亿” *美元的错误。抱歉,托尼·霍尔。星球上几乎所有可用的语言。

托尼·霍尔(Tony Hoare)解释

*我调整了托尼·霍尔(Tony Hoare)创造的表达方式,以反映这几天的实际损失:-)


这不是功能或错误,而是缺少功能。拥有不可为空的引用类型并不是您可以轻易地使用一种语言的东西;它需要大量的思考和良好的设计,并且很难以不希望与编译器抗衡的方式进行。Spec#和奇点表明它有多难。
imgx64 2010年

@ imgx86,不,绝对是错误的。不可为空的引用类型是为响应null错误而添加的功能,以允许与通常允许null的类型系统兼容。
马特·奥莱尼克

@Kyralessa:也许他想确保HoLyVieR获得了民粹主义徽章?:-)我同意,接受您自己的答案是没有意义的。
Macneil 2010年

18

C和C ++宏。如果由于有人为宏选择了标准函数名称而使我的代码搞砸了,而我又不得不看到另一个编译器错误,我将大声疾呼。让我们看看最后一个令人讨厌的地方:

#define vector(int) new VARIANT[int];

啊!您对我的STL向量做了什么!?


名称间隔是使typedef和模板立即更友好的原因之一。
Shog9

4
同意,但这仅是因为现代语言已经找到了文本宏功能的替代品。早在发明宏时,宏就是一件好事,因为编译器技术是如此原始。
dsimcha 2010年

您在哪里找到此宏?
rwong

@dsimcha-我对此一无所知。Lisp宏已经存在很长时间了。
杰森·贝克

2
@Jason:我不是要敲击Lisp风格的“真正的” AST宏,它们仍然有用而且很酷。我只讨厌C / C ++风格的宏,这些宏仅在文本级别工作,没有范围的概念,允许一个人创建荒谬的泄漏抽象和混淆的代码,并且可以被更现代的功能完全淘汰,其中之一具有讽刺意味,是“真实的”宏。
dsimcha,2010年

14

默认情况下,C和C ++ switch语句中的fallthrough。


18
在我编写的所有代码中,这始终是一个有用的功能。这怎么不适合?
greyfade

6
@greyfade:这很有用,直到您忘记该break语句,或者有人在两个案例之间添加一个案例(或重新排序),而不会注意到它们之间存在冲突。我没有看到任何方式下通是不是要求无论是休息或goto情况等的C#更好的方式
蒂姆·古德曼

9
Duff的设备嘲笑您有罪不罚!
Jesse C. Slicer

3
我同意。默认情况下不是一个好功能。

11
没人读吗?他说,下通默认
马特Olenik

13

当隐式类型转换之间没有明显的关系时。例如,将类似PHP 的随机非数字string转换为int


7
应该注意的是,一旦您掌握了这一点,这种事情就不会成问题了。如果您不对用户输入的值在关键区域中进行任何检查,那只会是一个真正的问题,但是,例如,如果您知道某个东西将是一个数字,而是一个字符串,那么它将无穷无尽。例如,数据库中的字段可能会以字符串形式返回,而您不必担心要强制转换它。
Tarka 2010年

2
@Slokun:你能提出一个更好的例子吗?为什么要使用字符串类型将整数值存储在db中?
史蒂文·埃弗斯

@SnOrfus获取在URL,用户输入,函数以及非静态类型语言常见的其他内容中传递的数字。
TheLQ

这也是C语言中的一个问题,因为带引号的字符串的值是一个指针,可以将其转换为整数,这可以使看起来像它们的结构正确编译但会产生废话。在C ++中,您可以使用关键字定义转换函数,该函数explicit可以停止隐式类型转换,但是仍然存在问题。
David Thornley,2010年

@TheLQ:如果是用户输入,则必须对其进行验证才能确定是否为数字。就像@Slokun说的那样。如果您正在从文件中读取数据,则可以期望数值数据位于应有的位置,但是在磁盘损坏的情况下引发异常通常比仅随机0获取某个值要好。
直觉


11

没有

仅因为频繁使用某个功能并不会造成危害。

恕我直言,整个“被认为是有害的”是编程语言讨论的还原

大多数(即使不是全部)“有害”功能都具有或最初具有非常有效的用例,或者首先只是方便的方法。开发人员需要了解其优缺点并相应地进行编码。

如果您的问题是按照“哪些语言功能具有常见的陷阱或不幸的副作用”来解决的,那么我的答案将有所不同。

[编辑]要明确:我并不是说继续使用不赞成使用的方法。如果开发人员要折旧/删除功能,则应使用替换功能。我指的是该语言的当前部分被认为是有害的,因为有些人不喜欢它所鼓励的内容或许多人讨论过的使用它所涉及的取舍。


13
我不同意,我的答案是一个很好的反例。PHP全局注册非常糟糕,您如何使用它们都无济于事。这就是为什么它已被弃用,强烈建议不要在旧版本的PHP上使用。
HolyVieR

5
+1放错手,任何语言构造都是有害的。
mouviciel 2010年

5
好点...即使goto方法的95%是坏的,该功能本身仍然是值得拥有的其他5%
EDS

1
我认为这更像是将弹出器座椅按钮放在收音机的开/关按钮旁边。该功能本身可能还不错,但是并不能防止由于意外使用它而造成的损害。
LennyProgrammers

1
我认为这在编程上相当于“枪不杀人,人杀人”。
2010年


7

PLEASE在INTERCAL中。它抱怨说,没有足够使用它。抱怨太多。


2
该语言不应被认真使用。它被创建为一种非常“独特”的编程语言,因此它充满了无用的东西(例如,来自我的脑海)。
ShdNx

4
我以为这很明显,但是是的,我知道这不是一种严肃的语言。
艾伦·皮尔斯

2
抱歉,这附近有些人太认真了。
Mark C 2010年

1
上周才在Wikipedia上发现了该语言,并被它的流行程度(仍然是O_O)所震撼。
奥利弗·韦勒

有许多“挑战性”语言,它们总是很流行,因为编码人员由于热衷于追逐而倾向于从事这项工作。由于它们刻板的钝角,发人深省的思想和刻苦,在面试问题中也很受欢迎。
2010年

7

尽管有些人不同意这个人或他所说的各种说法,但很多道格拉斯·克罗克福德(Douglas Crockford)的JavaScript:The Good Parts基本上就是这个问题,适用于JS。在克罗克福德的抱怨中:

  • 默认情况下,所有内容都具有全局作用域(DC展示了如何将函数/对象用作名称空间和作用域定界符,以解决此问题。)

  • 诸如之类的语句with,其失败行为是在全局命名空间中定义事物。(Gah!就像JS座右铭一样,如果您失败了,那么就尽可能失败!)

  • ==操作员的意外行为,这基本上要求您始终使用===操作员。

  • 分号插入。

实际上,很多JS应该被认为是有害的,甚至是整个语言也应该被认为是有害的,但是好的部分实在是太好了,以至于弥补了它(至少对我而言)。


6

在Flash Player中“默认失败”是默认行为

好的,这并不是语言本身的功能,但仍然紧密相关。

突然,您的Flash / Flex应用程序停止运行,没有人能给您丝毫提示f *发生了什么。没有错误信息,没有堆栈跟踪,什么都没有。只是突然之间就不会发生屏幕转换(或完全错误地发生),或者按钮不再对单击做出反应,或者组合框为空,而不是填充了某些条目。

单单是“功能”就引起了许多耸耸肩的报道以及我得到的一堆白发。-.-虽然也不希望在用户脸上弹出一些隐秘消息,但这至少可以帮助开发人员解决问题。

但是Flash Player会依靠用户的描述让您在黑暗中st刀(而问题实际上可能源自代码中完全不同的位置,与用户的操作没有任何关系)。仅当您使用调试播放器时,您实际上会获得带有错误消息和堆栈跟踪的弹出窗口。

但是,在某些新闻站点上观看嵌入的Flash电影并从使用的嵌入播放器SWF中获得有关Null引用的重复消息可能会非常有趣。:D


在某些怪异的时间,iPhone应用有时也会在没有警告的情况下崩溃
Ming-Tang

3
默默地失败任何事情都是很糟糕的。

6

在C / C ++中:这些赋值也是与非常相似的assign =和compare ==运算符组合的表达式。本身并不是有害的功能,但是它是通过不小心误操作员而易于引入(有时是细微的)错误的方法。

int i = 10;

someCode();

if(i = 5)
{
    /* We don't want this block to be executed, but it is */
    moreCode();
}

...结合一个整数或指针是有效条件的事实。
barjak 2012年

5

Java中的访问修饰符,默认为包私有语言,默认为私有编程约定。


5

在外壳中使用空字符串替换未定义的变量,而不会发出任何警告:rm -rf $nosuchvar/*


+1啊!大声笑-可怕的默认设置(以及有趣/令人恐惧的例子)
2010年

@Orbling类似的东西${varname:-/dev/null}可能是一种解决方法...
duros

好吧,这表明需要始终在使用前防御性检查变量的存在和内容。
2010年

4

可以逆时针旋转LOGO。WTF,让我们顺时针旋转360 - x角度。


嗯,自从我使用LOGO已经有一段时间了。为什么这有害?
梅森惠勒2010年

5
徽标可用于控制真正的物理乌龟机器人。有时您希望乌龟转向特定方向,或者不止一次转向。例如,也许您正在编程以进行某种舞蹈。
Daniel Cassidy

@梅森,这应该是个玩笑。
jjnguy 2010年

3
是的,尤其是在LOGO for Clocks中。
直觉

1
我喜欢徽标(请参阅developers.stackexchange.com/questions/21028/…),它是一种出色的教学语言,尤其是对于年轻人而言。当我说11并首次使用徽标时,我班上的大多数人都不知道那么多几何形状,但是他们被告知90是四分之一转,并且知道从右到左。因此,这不是负面特征-与为什么我们不乘以倒数而不是使用除运算符相同。是的,我知道这是个玩笑。
2010年

4

从另一个线程停止线程

在Java和其他语言中,您可以任意停止另一个线程,而不必花时间让停止的线程正确完成。考虑到可能在几乎所有情况下带来的大量问题,不建议使用此功能。


虽然我认为这可能是有害的,但有时它非常有用(例如,调试器支持单个步进和断点)。
杰里·科芬

1
@Jerry Debugging完全是另一回事,它不会停止该过程,而是会暂停它。
HolyVieR

相反,它将停止线程。显然,您是在谈论杀死线程,而不仅仅是停止线程。这有点难以辩解……
杰里·科芬

我认为这不一定是一种语言功能。更标准的东西。
杰森·贝克

4

PHP中的变量变量

只是因为你$can并不意味着你$$should


1
像往常一样,Perl ...具有可用的(潜在危险)功能,有一种简单的最佳实践方式将其关闭(use strict),并有一种在特定情况下再次将其重新开启的简便方法(no strict 'refs')。

1
我从未发现使用动态变量名称。而且我仅有的几次这样做,使代码变得不可读,几个月后,当我重新访问代码时,它又变成了WTF。
TheLQ

嗯,应用程序包括使用其他人讨厌的软件包变量或符号表进行元编程(我想这是一个很小的不同)。

1
@Joe我想向您展示一个示例,其中变量变量使解决方案更清晰。
肯德尔·霍普金斯

1
注释开个玩笑而已,对不起,我没有说清楚,但既然你问这里是最好的例子,其中可变的变量做出的解决方案更清晰。我承认这是一个相当糟糕的例子。
Joe D

3

With想到了Delphi中的声明,尽管在某些情况下它很有用。


当我将某些东西从Delphi移植到Lazarus并且我的TControl后代包含“使用Canvas do ... Width,Height”引用控件的大小时是一个好例子,但是Lazarus TCanvas具有自己的Width和Delphi,因此这导致了错误地编译代码
Maksee 2012年


2

在Perl中,标量上下文与列表上下文比较棘手。它有一些使某些操作变得方便的优点,但是有时您会遇到一些可怕的事情,例如完全改变运算符的含义(可能在代码中很远的距离)。

sub foo { (1..5) }
my @list = foo();           # (1,2,3,4,5)
my $length = scalar @list;  # 5. the length of the list.
my $length2 = scalar foo(); # '' (the empty string. because it's false)

那是不对的。

(它源于试图使行为类似于常规范围运算符的行为,因此您可以像那样在循环中说出一些东西next if /start_regex/ .. /end_regex/)。


人是如此混乱。学习Perl的最糟糕的事情是试图让我明白这一点。
glenatron

我一直认为,任何允许函数以多种方式返回的东西都非常方便。
2010年

2

Python 2.x的相对导入语法。假设我有一个软件包x.plugins,该软件包增加了对的其他各种库的支持x。并假设我有一个sqlalchemy模块,x.plugins以便可以向中添加sqlalchemy支持x。如果将以下行添加到sqlalchemy.py,您会怎么办?

import sqlalchemy

答案是该模块将尝试自行导入。这种语法的作用实际上是使不可能导入实际的全局sqlalchemy包。Python 2.5添加了一种指定这是相对导入的方式:

from . import sqlalchemy

...但是直到Python 3才真正摆脱了第一种语法(尽管可以使用禁用Python 2.6+中的语法from __future__ import absolute_import)。


1

我一直都喜欢sun.misc.unsafe;“我们需要用它来实现事物,但实际上,真的不认为您应该使用它。”


7
每种好的语言在标准库中都应该有一个不安全的程序包。导入此程序包可以清楚地表明您打算执行低级的不可移植的事情。替代方法是:1-在语言本身中具有不安全的功能(例如C ++),以及2-必须使用其他语言(例如C)来执行低级操作(例如Python和Ruby)。对于我来说,不安全的包装方法似乎要好得多。
imgx64 2010年

1

FORTRAN通用块。如果您犯了一个简单的错误,则应用程序的一部分可能破坏另一部分的全局变量。

FORTRAN分配了goto语句/ COBOL alter语句。自修改代码。危险,警告,飞行的意大利面条怪物!!


FORTRAN没有ALTER语句。FORTRAN具有ASSIGN语句以及已分配的GOTO。COBOL的ALTER语句具有相似的目的。
约翰·斯特罗姆

@约翰-谢谢。我对分配/更改的记忆是暗淡的……尤其是因为有人教我不要使用它们。
Stephen C

1

面向对象(来自所有静态类型的语言)。我敢打赌,这个功能已经并将继续,成本大大超过空指针。面向对象仅在动态消息传递语言中才有用。因此,它也应该从诸如Python的动态语言中删除(因为它不使用消息传递,而是使用常规的子例程调用)。


Python支持(出于所有意图和目的)smalltalk的消息传递惯用法。它只是没有这样命名。其次,我认为将这种普遍的语言功能称为有害至少是值得商de的。
杰森·贝克

面向对象仍然可以改善代码重用和代码/数据封装。无论功能的静态/动态用途如何。
2010年

@Orbling:相比什么?在我看来,函数式编程语言具有更高的代码重用性,我认为Haskell的模块系统非常适合代码/数据封装。
LennyProgrammers 2010年

@ Lenny222与标准命令式编程相比。我也更喜欢函数式方法,Haskell是我的首选语言。
2010年

@Jason Baker:毫无疑问,这是值得商bat的,但是如此普及却恰恰是它如此有害的原因!OP确实征求了我的意见,我给出了意见。仅仅因为一群Lemmings跳下悬崖并不能使行为保持理智。在这种情况下,已经在数学上证明了OOP不起作用,并且正确的范例已得到广泛接受:类别理论是表示抽象的方式(实际上是抽象的理论)
Yttrill

1

magic_quotes在PHP中

没有经验的开发人员要么依赖于启用它,然后假定所有用户输入都被转义以用于SQL查询,要么依赖于其被禁用,因此始终转义其输入。

假设已启用它,然后在未安装它的系统上运行代码,则会打开巨大的SQL注入孔。

假设已禁用(而不是禁用),则会导致反斜杠实际存储在数据库中,从而导致字符串难看/不正确。

也没有一种非常简单的方法来处理这两种情况-您需要检查是否已启用使用get_magic_quotes_gpc(),然后将其应用于数组中的stripslashes()所有值$_*-由于array_map这不是递归的,因此您需要一个自定义函数。


或者,您可以只使用参数化查询。
Pieter B

即使这样,如果启用了魔术引号,而且您没想到它也会得到反斜杠。
ThiefMaster 2012年

-3

语言功能,使程序员可以编写未注释或无意义的代码。


1
以及如何解决这个问题?
Maniero

1
@bigown:通过实现注释或模具功能:D。
tia

3
这就是所谓的Literate Programming。en.wikipedia.org/wiki/Literate_programming
巴里·布朗

2
这不是一个功能,但是它是用户前端中一个非常著名的错误,大多数人都以其拉丁名称Homo Sapiens知道。
乔D

-3

在这里四肢伸出一点-无效功能。函数总是执行某项操作,因此它应该返回结果或有关其成功或失败的其他信息。


3
Pascal具有过程(无返回值)和函数(返回值)。
乔恩·昂斯托特

函数总是会做某事(通常,占位符会起作用吗?),但通常不需要告诉任何人。
2010年

-4

基本的POKE ...


7
POKE很棒。
Shog9

2
在早期,戳戳是您可以基本实现某些目标的唯一合理方法。苹果上的音乐] [浮现在脑海中……
比尔

2
如果我没记错的话,没有Commodore 64上的POKE,您将无法做很多事情。
MetalMikester 2010年

1
别忘了PEEK,两者都很重要。
2010年

-5

我不得不说垃圾收集。它并没有消除对内存管理的思考,而是消除了内存管理的思考的感觉,而内存管理常常会消除实际的想法,从而导致大量的资源消耗,并且不知道为什么。尤其是当可以将现代世代GC的行为描述为没有过多夸张的情况时,无论如何都是“设计导致的一次大内存泄漏”。


2
如果您在某处的某个收藏中有参考文献,则还有其他问题。
Chinmay Kanchi 2010年

2
这就是为什么gc语言的参考文献薄弱:)
Chinmay Kanchi

4
尽管GC当然有优点也有缺点,但我不得不说梅森在这件事上是对是错。实际上,我已经看到使用GC的人在内存管理上花费了很多额外的时间,因为他们最终在事实发生后试图破解某些东西,而不是事先进行计划。GC通常还可以防止确定性破坏,这会导致管理内存以外的所有资源所需的额外工作。
杰里·科芬

3
@ChaosPandion:如果我认为在现代多任务计算机上,为了防止页面调度破坏系统性能,应该尽快释放内存,我真的是个傻瓜吗?没有一个GC甚至无法接近达到这个结果,实际上,世代垃圾收集器被认为是最好的,最现代的垃圾收集器,其作用恰恰相反:为了获得最佳性能,必须释放它记忆越越好。我没有发现它曾经是适合任何工作的合适工具,而不是它减慢了我的其他程序的速度。我是傻子吗?
梅森·惠勒

2
@Barry:在程序中是确定性的。如果我已经用完了5 KB的内存块,然后不久再要求另外5 KB,会发生什么?在垃圾回收系统中,即使有一个非常好的块闲置,它也需要请求一个5 KB的新块,除非GC已在此期间运行,在这种情况下,您可以回收旧块。使用malloc和free,您将始终能够回收旧块。乘以数十万,这便成为一个现实问题。
梅森惠勒

-5

C,当然还有C ++:指针算术。允许人们将整数转换为内存地址会带来麻烦。

甚至完全可以完全原始访问指针?

在C ++中,您具有使指针几乎完全不必要的引用。对于其余情况,应将智能指针视为强制性的。

Java还证明,您可以制作一种使用指针的编程语言,而无需允许人们访问指针值本身。

除了null...,那是一个不同的故事。


5
指针虽然有时很难正确使用,但对于大量有效的内存操作而言却是非常必要的。
比尔

1
真正。但是,在我看来,如今允许人们定期将整数转换为内存引用,或将数字添加到内存地址对大多数人都是有害的。在C ++中,您可以使用引用作为完美的替代方法,并在需要时将其用作智能指针/自动指针。
Asgeir S. Nilsen

4
当您使用隐藏指针的软件堆栈时,此答案有效。在所有其他情况下,此答案都是错误的。
保罗·内森

3
某些编程语言需要具有可用的指针,以便您可以为其他编程语言编写所有操作系统和虚拟机。

2
-1。有一个原因需要进行ptr运算:迭代点比建立索引快。for(int i=0;i<SIZE;++i) ++arr[i]比慢for(int*i=arr;i<arr+SIZE;++i)*i++。所有Java设法证明您确实需要指针,还是您从未看过sun.misc.Unsafe?如果不需要指针,请说明如何使用Java编写通用交换函数。(例如int a = 1,b = 2; swap(a,b); assert(a == 2 && b == 1);)。更不用说如果您不得不使用引用,则会在c / c ++中遇到所有问题。您如何在不带指针的不透明结构上调用虚拟函数?
KitsuneYMG 2010年
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.