我知道匈牙利语所指的内容 - 将有关变量,参数或类型的信息作为其名称的前缀。每个人似乎都狂热地反对它,尽管在某些情况下它似乎是一个好主意。如果我觉得有用的信息被传授,为什么我不能把它放在那里?
另请参阅:Do people use the Hungarian naming conventions in the real world?
答案 0 :(得分:277)
v使用匈牙利语符号vmakes nread ncode很难。
答案 1 :(得分:174)
大多数人以错误的方式使用匈牙利表示法并且得到错误的结果。
阅读Joel Spolsky撰写的这篇优秀文章:Making Wrong Code Look Wrong。
简而言之,使用type
(字符串)(系统匈牙利语)为变量名前缀的匈牙利表示法很糟糕,因为它没用。
匈牙利表示法,因为它的作者有意为变量名称加上kind
(使用Joel的例子:安全字符串或不安全的字符串),因此所谓的Apps匈牙利语有其用途并且仍然很有价值。< / p>
答案 2 :(得分:104)
乔尔错了,这就是原因。
他正在谈论的“应用程序”信息应该在类型系统中进行编码。您不应依赖于翻转变量名称以确保不将不安全数据传递给需要安全数据的函数。您应该将其设置为类型错误,以便不可能这样做。任何不安全的数据都应该有一个标记为不安全的类型,因此它根本无法传递给安全函数。要从不安全转换为安全,应该要求使用某种消毒功能进行处理。
乔尔所说的“种类”的许多东西都不是种类;事实上,它们是类型。
然而,大多数语言缺乏的是一种表达系统,其表现力足以强制实施这些区别。例如,如果C有一种“强类型定义”(其中typedef名称具有基类型的所有操作,但不能转换为它),那么很多这些问题就会消失。例如,如果您可以说,strong typedef std::string unsafe_string;
引入了一个无法转换为std :: string的新类型unsafe_string
(因此可以参与重载解析等等),那么我们会不需要愚蠢的前缀。
因此,匈牙利人对于非类型事物的主要说法是错误的。它被用于类型信息。比传统的C型信息更丰富的类型信息,当然;它的类型信息编码某种语义细节以指示对象的目的。但它仍然是类型信息,正确的解决方案一直是将其编码到类型系统中。将其编码到类型系统中是获得适当验证和规则执行的最佳方式。变量名称根本不会削减芥末。
换句话说,目标不应该是“让错误的代码看起来对开发者来说错误”。它应该是“使错误的代码看起来错误到编译器”。
答案 3 :(得分:46)
我认为它大大混乱了源代码。
使用强类型语言也不会带来太多好处。如果你做任何形式的类型不匹配tomfoolery,编译器会告诉你它。
答案 4 :(得分:28)
匈牙利表示法仅适用于没有用户定义类型的语言。在现代函数或OO语言中,您可以将有关“类型”值的信息编码到数据类型或类中,而不是编码到变量名中。
有几个答案参考Joels article。但请注意,他的示例是在VBScript中,它不支持用户定义的类(至少很长一段时间)。在具有用户定义类型的语言中,您可以通过创建HtmlEncodedString类型来解决相同的问题,然后让Write方法仅接受该类型。在静态类型语言中,编译器将捕获任何编码错误,在动态类型中您将获得运行时异常 - 但无论如何您都可以防止编写未编码的字符串。匈牙利语符号只是让程序员变成了一个人类型检查器,这种工作通常可以通过软件更好地处理。
Joel区分“匈牙利系统”和“匈牙利应用程序”,其中“匈牙利系统”编码内置类型,如int,float等,“apps hungarian”编码“种类”,这是更高级别的关于变量的元信息beyound机器类型,在OO或现代函数语言中,您可以创建用户定义的类型,因此在这种意义上类型和“种类”之间没有区别 - 两者都可以由类型系统表示 - 和“应用程序”匈牙利语与匈牙利语“系统”一样多余。
所以要回答你的问题:系统匈牙利语只适用于不安全的弱类型语言,例如:将float值赋给int变量会使系统崩溃。匈牙利符号是在六十年代专门发明的,用于BCPL,这是一种非常低级的语言,完全没有进行任何类型检查。我不认为今天普遍使用的任何语言都有这个问题,但这种符号仍然存在于cargo cult programming中。
如果您正在使用没有用户定义类型的语言(如旧版VBScript或早期版本的VB),那么应用匈牙利语将有意义。也许早期版本的Perl和PHP也是如此。再次,在现代语言中使用它是纯粹的货物崇拜。
在任何其他语言中,匈牙利人只是丑陋,多余和脆弱。它重复了类型系统中已知的信息,you should not repeat yourself。对描述此特定类型实例的意图的变量使用描述性名称。使用类型系统来编码变量的“种类”或“类”的不变量和元信息 - 即。类型。
Joels文章的一般观点 - 错误的代码看起来错了 - 是一个非常好的原则。然而,更好的防止错误的方法是 - 尽可能 - 编译器自动检测错误的代码。
答案 5 :(得分:27)
我总是在我的所有项目中使用匈牙利表示法。当我处理100个不同的标识符名称时,我发现它真的很有用。
例如,当我调用一个需要字符串的函数时,我可以输入's'并点击控制空间,我的IDE将向我显示前缀为's'的变量名。
另一个优点是,当我为无符号前缀和我为有符号整数添加前缀时,我立即看到我在哪里以有潜在危险的方式混合有符号和无符号。
我记不起在一个巨大的75000行代码库中由于命名局部变量与该类的现有成员变量相同而导致错误(由我和其他人造成)的次数。从那以后,我总是在成员前面加上'm _'
这是一个品味和经验的问题。在你尝试之前不要敲它。
答案 6 :(得分:22)
您忘记了包含此信息的首要原因。这与程序员无关。在你离开必须阅读这些东西的公司2到3年后,这与那些下路的人有关。
是的,IDE会快速为您识别类型。但是,当您阅读一些长批量的“业务规则”代码时,不必在每个变量上暂停以找出它是什么类型。当我看到像strUserID,intProduct或guiProductID这样的东西时,它会使很多更容易“加速”时间。
我同意MS对他们的一些命名惯例走得太远了 - 我把它归类为“太多好事”。
命名约定是好事,只要你坚持下去。我已经经历了足够多的旧代码,让我不断回头看看这么多类似命名的变量的定义,我推“骆驼套管”(因为它在之前的工作中被调用)。现在我的工作中有数千条完全没有注释的经典ASP代码和VBScript,这是一个噩梦,试图解决问题。
答案 7 :(得分:10)
在每个变量名称的开头处加密隐藏字符是不必要的,并且表明变量名称本身不够具有描述性。无论如何,大多数语言都需要声明变量类型,因此信息已经可用。
还有一种情况是,在维护期间,变量类型需要更改。示例:如果声明为“uint_16 u16foo”的变量需要成为64位无符号变量,则会发生以下两种情况之一:
答案 8 :(得分:9)
Joel Spolsky撰写了一篇关于此事的好博文。 http://www.joelonsoftware.com/articles/Wrong.html 基本上,它归结为如果你不记得,当一个体面的IDE会告诉你想要输入变量时你的代码更难以阅读。此外,如果您使代码足够分隔,则不必记住变量被声明为三页。
答案 9 :(得分:9)
这些天不是范围更重要,例如
* l for local
* a for argument
* m for member
* g for global
* etc
使用现代技术重构旧代码,搜索和替换符号因为你改变了它的类型是繁琐的,编译器会捕获类型更改,但通常不会捕获不正确的范围使用,合理的命名约定在这里有帮助。
答案 10 :(得分:8)
没有理由不让正确使用匈牙利表示法。它的不受欢迎是由于长期反对匈牙利表示法的误用,尤其是在Windows API中。
在过去的糟糕日子里,在DOS之前存在类似于IDE的任何东西(可能你没有足够的可用内存来运行Windows下的编译器,所以你的开发是在DOS下完成的),你没有得到将鼠标悬停在变量名称上的任何帮助。 (假设你有一个鼠标。)你所要处理的是事件回调函数,其中所有内容都以16位int(WORD)或32位int(LONG WORD)的形式传递给你。然后,您必须将这些参数强制转换为给定事件类型的相应类型。实际上,大部分API实际上都是无类型的。
结果,一个带有如下参数名称的API:
LRESULT CALLBACK WindowProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam);
请注意,名称wParam和lParam虽然非常糟糕,但实际上并不比命名param1和param2差。
更糟糕的是,Window 3.0 / 3.1有两种类型的指针,远近。因此,例如,内存管理函数LocalLock的返回值是PVOID,但GlobalLock的返回值是LPVOID(长度为'L')。那个可怕的符号然后被扩展,以便 l ong p ointer字符串以 lp 作为前缀,以区别于仅仅是malloc的字符串“d。
对这种事情产生强烈反对并不奇怪。
答案 11 :(得分:6)
作为一名Python程序员,匈牙利表示法很快就会崩溃。在Python中,我不在乎是字符串 - 我关心它是否像字符串一样(即它是否有___str___()
方法返回一个字符串)。
例如,假设我们将foo作为整数,12
foo = 12
匈牙利表示法告诉我们,我们应该调用iFoo或其他东西,以表示它是一个整数,以便稍后,我们知道它是什么。除了在Python中,这不起作用,或者更确切地说,它没有意义。在Python中,我决定在使用它时我想要什么类型。我想要一个字符串吗?好吧,如果我做这样的事情:
print "The current value of foo is %s" % foo
请注意%s
- 字符串。 Foo不是字符串,但%
运算符将调用foo.___str___()
并使用结果(假设它存在)。 foo
仍然是一个整数,但如果我们想要一个字符串,我们将其视为一个字符串。如果我们想要一个浮点数,那么我们将它视为一个浮点数。在像Python这样的动态类型语言中,匈牙利表示法是没有意义的,因为在你使用它之前它与什么类型无关,如果你需要一个特定的类型,那么只需确保将它转换为该类型(例如{{1当你使用它时。
请注意,像PHP这样的动态语言没有这个好处 - PHP试图在后台基于一组几乎没有人记忆的模糊规则来做“正确的事”,这通常会导致意外的灾难性混乱。在这种情况下,某种命名机制(如float(foo)
或$files_count
)可以很方便。
在我看来,匈牙利表示法就像水蛭一样。也许在过去它们很有用,或者至少看起来很有用,但是现在它只是为了获得很多好处而进行了大量的额外打字。
答案 12 :(得分:6)
匈牙利表示法在没有编译时类型检查的语言中非常有用,因为它允许开发人员快速提醒自己如何使用特定变量。它对性能或行为没有任何作用。它应该提高代码的可读性,主要是品味和编码风格。由于这个原因,许多开发人员批评它 - 并非每个人都有相同的大脑接线。
对于编译时类型检查语言,它几乎没用 - 向上滚动几行应该显示声明,从而显示类型。如果全局变量或代码块跨越多个屏幕,则会出现严重的设计和可重用性问题。因此,其中一个批评是匈牙利表示法允许开发人员设计糟糕并轻松逃脱。这可能是受到仇恨的原因之一。
另一方面,甚至可能存在编译时类型检查语言将从win32中的匈牙利表示法 - void 指针或 HANDLE 中受益的情况API。这些混淆了实际的数据类型,在那里使用匈牙利表示法可能有一些优点。但是,如果可以在构建时知道数据类型,为什么不使用适当的数据类型。
一般来说,没有硬性理由不使用匈牙利表示法。这是一个喜欢,政策和编码风格的问题。
答案 13 :(得分:5)
IDE应该传授有用的信息。当IDE不太先进时,匈牙利人可能会做出某种意义(不是很多,但是某种意义上的)。
答案 14 :(得分:5)
作为一名工程师而非程序员,我立即接受了Joel关于Apps匈牙利语"Making Wrong Code Look Wrong"的优点的文章。我喜欢Apps Hungarian,因为它模仿工程,科学和数学如何使用子脚本和超脚本符号表示方程式和公式(如希腊字母,数学运算符等)。以Newton's Law of Universal Gravity为例:首先是标准数学符号,然后是Apps匈牙利语伪代码:
frcGravityEarthMars = G * massEarth * massMars / norm(posEarth - posMars)
在数学符号中,最突出的符号是那些代表存储在变量中的信息种的符号:力,质量,位置向量等。下标是第二小提琴澄清:位置什么?这正是Apps匈牙利人正在做的事情;它首先告诉你存储在变量中的事物的种然后进入细节 - 关于最接近的代码可以得到数学符号。
显然强类型可以解决Joel的文章中的安全与不安全的字符串示例,但是你不会为位置和速度向量定义单独的类型;两者都是三号的双重数组,你可能对一个人做的任何事都可能适用于另一个。此外,连接位置和速度(制作状态向量)或取其点积非常有意义,但可能不会添加它们。如何打字允许前两个并禁止第二个,这样的系统将如何扩展到您可能想要保护的每个可能的操作?除非您愿意在打字系统中对所有数学和物理进行编码。
最重要的是,许多工程都是在像Matlab这样的弱类型高级语言中完成的,或者是像Fortran 77或Ada那样的旧版本。
所以,如果你有一种奇特的语言和IDE,那么匈牙利应用程序对你没有帮助就会忘记它 - 很多人显然都有。但对于我来说,比使用弱动态或动态类型语言的新手程序员更糟糕的是,我可以使用匈牙利应用程序更快地编写更好的代码。
答案 15 :(得分:4)
大多数现代的IDE都是非常冗余和无用的,它们可以很好地使类型显而易见。
另外 - 对我来说 - 看到intI,strUserName等是很烦人的事情:))
答案 16 :(得分:4)
如果类型只是将一个值与另一个值区分开来,那么它只能用于将一种类型转换为另一种类型。如果您具有在类型之间转换的相同值,则可能应该在专用于转换的函数中执行此操作。 (我已经看到匈牙利的VB6剩余部分在所有方法参数上使用字符串只是因为他们无法弄清楚如何反序列化JSON对象,或者正确理解如何声明或使用可空类型。)如果你有两个变量仅由匈牙利语前缀区分,并且它们不是从一个到另一个的转换,那么你需要详细说明你的意图。
我发现匈牙利表示法让人们变量名称变得懒散。他们有一些东西可以区分它,他们觉得没有必要详细说明它的目的。这是您在匈牙利标记代码与现代代码中通常会发现的内容:sSQL与groupSelectSql(或通常根本没有sSQL,因为它们应该使用早期开发人员提供的ORM。 ),sValue与formCollectionValue(或通常没有sValue,因为它们碰巧在MVC中,应该使用其模型绑定功能),sType与publishSource等。
它不具备可读性。我从任何给定的匈牙利VB6剩余部分看到的sTemp1,sTemp2 ...... sTempN比其他人的总和还多。
这将取决于数字2,这是错误的。
答案 17 :(得分:4)
Joel的文章很棒,但它似乎省略了一个重点:
匈牙利人将特定的“想法”(种类+标识符名称)设为唯一, 或者在代码库中几乎是独特的 - 甚至是一个非常大的代码库。
这对于代码维护来说是巨大的。 这意味着你可以使用好的单行文本搜索 (grep,findstr,'在所有文件中找到')找到每个提及这个'想法'。
当我们知道如何读取代码的IDE时,为什么这很重要? 因为他们还不是很擅长。这在小代码库中很难看到, 但是很明显 - 在评论中可能会提到“想法”时 XML文件,Perl脚本,以及源代码控制之外的地方(文档,维基, 错误数据库)。
即使在这里你也必须要小心 - 例如C / C ++宏中的令牌粘贴 可以隐藏标识符的提及。这种情况可以使用 编码约定,无论如何它们往往只会影响到少数几个标识符 代码库。
P.S。关于使用类型系统与匈牙利语的关系 - 最好同时使用两者。 如果编译器不能为您捕获它,您只需要错误的代码就会出错。有很多情况下编译器捕获它是不可行的。但是在可行的地方 - 是的,请这样做!
在考虑可行性时,请考虑拆分类型的负面影响。例如在C#中,用非内置类型包装'int'会产生巨大的后果。所以在某些情况下这是有道理的,但在所有情况下都没有。
答案 18 :(得分:4)
我倾向于将匈牙利表示法与ASP.NET服务器控件仅一起使用,否则我发现很难弄清楚窗体上的控件是什么。
获取此代码段:
<asp:Label ID="lblFirstName" runat="server" Text="First Name" />
<asp:TextBox ID="txtFirstName" runat="server" />
<asp:RequiredFieldValidator ID="rfvFirstName" runat="server" ... />
如果某人能够更好地掌握那套没有匈牙利语的控制名称,我会很想搬到它。
答案 19 :(得分:4)
我一直以为在正确的地方有一两个前缀不会受到伤害。我想如果我能传授一些有用的东西,比如“嘿,这是一个界面,不要依赖于特定的行为”,就像在IEnumerable中一样,我应该这样做。评论可能比一两个字符符号更容易混乱。
答案 20 :(得分:4)
在Joel Spolsky's Making Wrong Code Look Wrong中,他解释说每个人都认为匈牙利表示法(他称之为匈牙利语系统)不是真正意图的(他称之为匈牙利应用程序)。向下滚动到我是匈牙利标题以查看此讨论。
基本上,匈牙利系统毫无价值。它只是告诉您编译器和/或IDE将告诉您的相同内容。
应用程序匈牙利语告诉您该变量应该是什么意思,并且实际上可以有用。
答案 21 :(得分:4)
如果我觉得有用的信息被传授,为什么我不能把它放在那里?
然后谁在乎别人怎么想?如果您觉得它很有用,请使用符号。
答案 22 :(得分:4)
如果控件列表显示在IDE中按字母顺序排列的下拉列表中,那么在窗体上命名控件(btnOK,txtLastName等)是一个很有用的约定。
答案 23 :(得分:4)
我的经验,这很糟糕,因为:
1 - 如果需要更改变量的类型(即如果需要将32位整数扩展为64位整数),则会中断所有代码;
2 - 这是无用的信息,因为类型已经在声明中,或者你使用动态语言,其中实际类型首先不应该那么重要。
此外,使用一种接受泛型编程的语言(即在编写函数时未确定某些变量类型的函数)或动态类型系统(即在编译时甚至不确定类型)时,如何你命名你的变量?大多数现代语言都支持其中一种,即使是受限制的形式。
答案 24 :(得分:3)
用主人的话来说:
http://www.joelonsoftware.com/articles/Wrong.html
像往常一样有趣的阅读。
提取物:
“有人在某处阅读过Simonyi的论文,他在那里使用了”type“这个词,并认为他的类型就像类一样,就像类型系统一样,就像编译器所做的类型检查一样。他没有。他没有。他非常仔细地解释了“类型”一词的含义,但没有帮助。损坏已经完成了。“
“但匈牙利应用程序仍然有很大的价值,因为它增加了代码中的搭配,使代码更易于读取,编写,调试和维护,最重要的是,它使错误的代码看起来错误。“
确保您在阅读Joel On Software之前有一些时间。 :)
答案 25 :(得分:3)
有几个原因:
答案 26 :(得分:2)
我不认为每个人都狂热地反对它。在没有静态类型的语言中,它非常有用。当它用于提供不属于该类型的信息时,我肯定更喜欢它。就像在C中一样, char * szName 表示该变量将引用一个以null结尾的字符串 - 这不是隐含在char *中的 - 当然,typedef也会有所帮助。
Joel有一篇很棒的文章,关于使用匈牙利语判断一个变量是否是HTML编码:
http://www.joelonsoftware.com/articles/Wrong.html
无论如何,当我习惯传授我已经知道的信息时,我倾向于不喜欢匈牙利语。
答案 27 :(得分:2)
当然,当99%的程序员都同意某事时,就会出现问题。他们在这里同意的原因是因为他们中的大多数人从未正确使用匈牙利符号。
有关详细论据,我建议您参考我就该主题撰写的博客文章。
http://codingthriller.blogspot.com/2007/11/rediscovering-hungarian-notation.html
答案 28 :(得分:2)
我几乎开始编写关于匈牙利符号发明的时间,并且我第一次被迫在一个我讨厌它的项目中使用它。
过了一会儿,我意识到当它完成得当它确实有所帮助,这些天我喜欢它。
但是就像所有事情一样好,必须学会和理解,并且做得恰当需要时间。
答案 29 :(得分:1)
我认为审美方面的整个事情过于夸张。如果这是最重要的事情,我们不会称自己为开发人员,而是图形设计师。
我认为,一个重要的部分是你描述你的对象角色是什么,而不是它是什么。你不称自己为HumanDustman,因为在另一个背景下,你最重要的不是人类。
对于重构目的而言,它也非常重要:
public string stringUniqueKey = "ABC-12345";
如果您决定使用GUID而不是字符串,那么在重构所有引用代码后,您的变量名称看起来会很愚蠢。
或者:
public int intAge = 20;
将此更改为浮点数,您会遇到同样的问题。等等。
答案 30 :(得分:1)
匈牙利语符号被滥用,尤其是微软,导致前缀长于变量名称,并显示它非常严格,特别是当您更改类型(臭名昭着的Lparam / wparam,Win16中不同类型/大小,在Win32中相同。
因此,由于这种滥用行为以及M $的使用,它被视为毫无用处。
在我的工作中,我们用Java编写代码,但是创始人来自MFC世界,所以使用类似的代码样式(对齐的大括号,我喜欢这个!,大写到方法名称,我已经习惯了,像m_这样的前缀到类成员(字段),s_到静态成员等。)。
他们说所有变量都应该有一个显示其类型的前缀(例如,BufferedReader被命名为brData)。这显示为一个坏主意,因为类型可以改变,但名称不会跟随,或者编码器在使用这些前缀时不一致(我甚至看到aBuffer,theProxy等等。)。
就我个人而言,我选择了一些我觉得有用的前缀,最重要的是b为布尔变量加前缀,因为它们是我允许if (bVar)
之类语法的唯一前缀(不使用某些值的autocast)是真是假。
当我用C编码时,我使用了一个用malloc分配的变量的前缀,作为提示,它应该在以后释放。等
所以,基本上,我并没有拒绝这个符号作为一个整体,而是采取了适合我需要的东西 当然,在为某些项目(工作,开源)做贡献时,我只是使用了这些惯例!
答案 31 :(得分:0)
匈牙利语很糟糕,因为它会从变量名称中取出宝贵的字符来换取什么类型的信息?
首先,在强类型语言中,编译器会在你做任何真正愚蠢的事情时发出警告。
其次,如果您相信良好的模块化代码并且在任何1个函数中都没有做太多工作,那么您可能会在它们被使用的代码之上声明变量(因此您可以在那里使用类型)
第三,如果你给每个指针添加p前缀,每个类前面加上C,那么你真正搞砸了现代IDE的智能感知功能(你知道当你输入你输入的类名时它会猜到的功能吗?它是正确的你可以按Enter键并为它完成它?好吧,如果你在每个类前面加上C,你总是至少要输入1个字母)...
答案 32 :(得分:0)
我找不到链接,但我记得在某个地方(我同意)阅读,避免匈牙利表示法会带来更好的编程风格。
当你编写一个程序语句时,在调用它的方法之前你不应该考虑“这个对象是什么类型”,而是你应该想“我想用它做什么”,“哪个消息给发送给它“。
有点模糊的概念来解释,但我认为它有效。
例如,如果客户名称存储在变量customerName中,则不应该关心它是字符串还是其他类。更重要的是要从这个对象想想你想要什么。你想要它print(),getFirstName(),getLastName(),convertToString()等。一旦你使它成为一个String类的实例并将其视为被授予,你限制自己和你的设计,因为你必须建立所有代码中其他地方需要的其他逻辑。
答案 33 :(得分:0)
多年来我在编程中使用了匈牙利符号。除了一些视觉混乱和我改变数据类型时更改前缀的任务,没有人可以说服我。直到最近 - 当我必须在同一解决方案中组合现有的C#和VB.NET程序集时。
结果:我必须将“fltSomeVariable”传递给“sngSomeVariable”方法参数。即使是在C#和VB.NET中编程的人,它也让我措手不及,让我暂停一下。 (C#和VB.NET有时使用不同的名称来表示相同的数据类型 - 例如float和single。)
现在考虑一下:如果你创建一个可以从多种语言调用的COM组件怎么办?对于.NET程序员来说,VB.NET和C#“转换”很容易。但是那些用C ++或Java开发的人呢?对于不熟悉C ++的.NET开发人员来说,“dwSomeVariable”是否意味着什么?
答案 34 :(得分:0)
如果你没有被告知你不知道变量的类型,你可能不应该搞乱它
这种类型可能也不那么重要。如果您知道这些方法的作用,您可以弄清楚该变量的用途,然后您将了解该程序正在做什么
有时你可能想要它;当类型很重要且声明不接近或无法轻易推断出类型时。但它永远不应被视为绝对的
答案 35 :(得分:0)
答案 36 :(得分:0)