我知道匈牙利语指的是-提供有关变量,参数或类型的信息作为其名称的前缀。每个人似乎都在疯狂地反对它,即使在某些情况下,这似乎是一个好主意。如果我觉得正在传递有用的信息,为什么不把它放在可用的地方呢?
另请参阅:人们在现实世界中是否使用匈牙利命名约定?
我知道匈牙利语指的是-提供有关变量,参数或类型的信息作为其名称的前缀。每个人似乎都在疯狂地反对它,即使在某些情况下,这似乎是一个好主意。如果我觉得正在传递有用的信息,为什么不把它放在可用的地方呢?
另请参阅:人们在现实世界中是否使用匈牙利命名约定?
Answers:
大多数人以错误的方式使用匈牙利表示法,并且得到错误的结果。
阅读Joel Spolsky撰写的这篇出色文章:使错误的代码看起来错误。
简而言之,在匈牙利符号中用变量名type
(字符串)(Systems Hungarian)作为前缀是不好的,因为它没有用。
匈牙利注释法,正如它的作者所希望的那样,您在变量名前加上变量名kind
(使用乔尔的示例:安全字符串或不安全字符串),因此所谓的Apps Hungarian具有其用途,并且仍然很有价值。
使用匈牙利语注释vmake使ncode难以理解。
乔尔错了,这就是原因。
他正在谈论的“应用程序”信息应该在类型系统中编码。您不应该依赖于翻转变量名来确保不会将不安全的数据传递给需要安全数据的函数。您应该将其设置为类型错误,这样就不可能这样做。任何不安全的数据都应具有标记为“不安全”的类型,以便根本无法将其传递给安全功能。要从不安全状态转换为安全状态,应要求使用某种消毒功能进行处理。
乔尔所说的“种类”很多东西都不是种类。实际上,它们是类型。
但是,大多数语言所缺乏的是一种类型表达系统,足以表现出这种区别。例如,如果C具有一种“强typedef”(typedef名称具有基本类型的所有操作,但不能转换为基本类型),那么很多这些问题就会消失。例如,如果您可以说strong typedef std::string unsafe_string;
要引入一种unsafe_string
无法转换为std :: string 的新类型(因此可能会参与重载解析等),那么我们就不需要傻前缀了。
因此,关于匈牙利语适用于非类型事物的中心说法是错误的。它用于类型信息。当然,类型信息比传统的C类型信息更丰富;类型信息对某种语义细节进行编码,以指示对象的用途。但是它仍然是类型信息,正确的解决方案始终是将其编码为类型系统。将其编码到类型系统中是获得适当验证和执行规则的最佳方法。变量名称根本不会榨菜。
换句话说,目标不应是“使错误的代码对开发人员来说看起来是错误的”。应该是“使错误的代码对编译器来说是错误的 ”。
Joel is wrong
和What most languages lack, however, is a type system that's expressive enough to enforce these kind of distinctions.
那么,既然大多数语言都缺乏足够的表现来执行这些类型的区别,乔尔是正确的。对?
我认为它会使源代码变得混乱不堪。
使用强类型语言也不会给您带来多少好处。如果您进行任何形式的类型不匹配伪造,编译器都会告诉您。
匈牙利语表示法仅在没有用户定义类型的语言中才有意义。在现代的功能或OO语言中,您将有关值的“种类”的信息编码为数据类型或类,而不是变量名。
几个答案参考Joels的文章。但是请注意,他的示例在VBScript中,它不支持用户定义的类(至少很长一段时间)。在具有用户定义类型的语言中,您可以通过创建HtmlEncodedString-type然后让Write方法仅接受它来解决相同的问题。在静态类型的语言中,编译器将捕获任何编码错误,在动态类型的语言中,您将获得运行时异常-但是在任何情况下,都可以防止编写未编码的字符串。匈牙利语表示法只是将程序员转变为人工类型检查器,而这种工作通常可以由软件更好地处理。
Joel区分“系统匈牙利语”和“应用程序匈牙利语”,其中“系统匈牙利语”编码int,float等内置类型,而“应用程序匈牙利语”编码“种类”,这是高级元信息关于机器类型之外的变量,您可以在OO或现代功能语言中创建用户定义的类型,因此在这种意义上,类型和“种类”之间没有区别-两者都可以由类型系统表示-和“应用”匈牙利与“系统”匈牙利一样多余。
因此,回答您的问题:系统匈牙利语仅在不安全,弱类型的语言中有用,例如,将浮点值分配给int变量将使系统崩溃。匈牙利符号是六十年代特别发明的,用于BCPL,这是一种非常底层的语言,根本不进行任何类型检查。我认为今天没有一种通用的语言存在这个问题,但是这种符号作为一种“ 货物崇拜”编程而存在。
如果您使用的语言没有用户定义的类型(例如旧版VBScript或VB的早期版本),那么应用匈牙利语就有意义。也许还有Perl和PHP的早期版本。再次,在现代语言中使用它是纯粹的货物崇拜。
用任何其他语言,匈牙利人都是丑陋,多余和脆弱的。它重复了类型系统中已知的信息,因此您不应该重复自己。为变量使用描述性名称,以描述此特定类型实例的意图。使用类型系统对变量的“种类”或“类”进行不变式和元信息编码。类型。
Joels文章的总要点-使错误的代码看起来不正确-是一个很好的原则。但是,更好的防范错误的方法是-尽可能使编译器自动检测错误的代码。
我在所有项目中始终使用匈牙利表示法。当我处理100个不同的标识符名称时,我发现它真的很有帮助。
例如,当我调用一个需要字符串的函数时,我可以键入's'并点击control-space,我的IDE会准确地向我显示以's'为前缀的变量名。
另一个优点是,当我给u加上unsigned前缀而给i加上带符号的ints前缀时,我立即看到我在以潜在危险的方式混合有符号和无符号的地方。
我记不清多少次在庞大的75000行代码库中,由于将局部变量命名为与该类的现有成员变量相同而引起的错误(由我和其他人引起)。从那时起,我总是在成员前加上'm_'
这是口味和经验的问题。尝试之前请不要敲它。
您忘记了包括此信息的第一原因。与您无关,程序员。它与您离开公司后的2到3年内要读这本书的人有关。
是的,IDE将为您快速识别类型。但是,当您阅读大量的“业务规则”代码时,不必暂停每个变量来确定其类型是一件很不错的事情。当我看到像strUserID,intProduct或guiProductID,它使很多更容易'斜坡上升的时间。
我同意MS在某些命名约定方面走得太远-我将其归类为“太多了”。
只要您遵守命名约定,它们就是好东西。我已经经历了足够多的旧代码,使我不断地回头查看许多如此命名的变量的定义,以至于我推了“骆驼套”(在上一份工作中被称为)。现在,我从事的工作是使用VBScript编写成千上万行完全不加注释的经典ASP代码,这是一场噩梦,试图找出问题所在。
Joel Spolsky写了一篇很好的博客文章。 http://www.joelonsoftware.com/articles/Wrong.html 基本上可以归结为,当一个体面的IDE告诉您要键入变量时,如果您不记得了,就不会使您的代码难以阅读。另外,如果您对代码进行足够的分隔,则不必记住将变量声明为三页以上的内容。
这些天范围是否比键入更重要,例如
* l for local
* a for argument
* m for member
* g for global
* etc
使用现代的重构旧代码,搜索和替换符号的技术,因为您更改了符号的类型很乏味,因此编译器将捕获类型更改,但通常不会捕获对范围的不正确使用,明智的命名约定在这里有所帮助。
没有理由不应该正确使用匈牙利符号。之所以不受欢迎,是因为人们长期反对使用匈牙利符号,特别是在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具有两种类型的指针,near和far。因此,例如,内存管理功能LocalLock的返回值是PVOID,而GlobalLock的返回值是LPVOID(长时间带有“ L”)。那可怕的符号,然后得到了扩展,从而一升翁p ointer字符串是前缀LP,它从一切只是malloc分配的字符串区分。
反对这种事情也就不足为奇了。
匈牙利语表示法在不进行编译时类型检查的语言中很有用,因为它使开发人员可以快速提醒自己如何使用特定变量。它对性能或行为没有任何作用。它应该提高代码的可读性,并且主要是一种品味和编码风格。因此,许多开发人员都批评它-并非每个人的大脑都有相同的连线。
对于编译时的类型检查语言,它几乎是没有用的-向上滚动几行应该显示该声明并因此进行输入。如果全局变量或代码块跨越多个屏幕,那么您将面临严重的设计和可重用性问题。因此,批评之一是匈牙利符号法使开发人员的设计不好,并容易摆脱它。这可能是仇恨的原因之一。
另一方面,在某些情况下,甚至编译时类型检查语言也会受益于匈牙利符号-win32 API中的void指针或HANDLE。这些混淆了实际的数据类型,并且在那里使用匈牙利表示法可能会有好处。但是,如果可以在构建时知道数据的类型,为什么不使用适当的数据类型。
通常,没有硬性理由不使用匈牙利表示法。这取决于喜欢,政策和编码风格。
作为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)中,匈牙利表示法是没有意义的,因为在使用某种类型之前,它与什么类型无关紧要;如果需要特定类型,则只需确保将其转换为该类型即可(例如float(foo)
)用它。
请注意,动态语言(如PHP)没有此好处-PHP会根据一套几乎没人记住的晦涩规则来尝试在后台执行“正确的事情”,这通常会导致灾难性的混乱。在这种情况下,诸如$files_count
或的某种命名机制$file_name
可能会派上用场。
在我看来,匈牙利表示法就像水ches。也许在过去它们是有用的,或者至少它们似乎有用,但是如今,它只是带来了很多额外的好处而已。
.ToString()
以便可以全部打印出来
IDE应该提供有用的信息。当IDE不够先进时,匈牙利人可能会产生某种意义(不是很多,而是某种意义)。
作为工程师而不是程序员,我立即阅读了Joel撰写的有关Apps Hungarian优点的文章:“使代码看起来不正确”。我喜欢Apps Hungarian,因为它模仿工程,科学和数学如何使用子脚本和上标符号(例如希腊字母,数学运算符等)表示方程式和公式。以牛顿万有引力定律的特定示例为例:首先是标准数学符号,然后是Apps Hungarian伪代码:
frcGravityEarthMars = G * massEarth * massMars / norm(posEarth - posMars)
在数学符号中,最突出的符号是表示 变量中存储的信息种类的:力,质量,位置矢量等。下标起到第二个作用,以澄清:位置是什么?这正是Apps Hungarian所做的;它先告诉您存储在变量中的东西的种类,然后再告诉细节-关于最接近的代码可以用数学符号表示。
显然,强类型输入可以解决Joel文章中的安全字符串与不安全字符串的示例,但是您不会为位置和速度矢量定义单独的类型。两者都是大小为3的双数组,您可能对其中一个所做的任何操作都可能适用于另一个。此外,连接位置和速度(以生成状态向量)或获取其点积,但可能不添加它们,是非常有意义的。键入将如何允许前两个而禁止第二个,这样的系统将如何扩展到您可能想要保护的所有可能的操作?除非您愿意在打字系统中对所有数学和物理学进行编码。
最重要的是,许多工程都是使用弱类型的高级语言(如Matlab)或旧语言(如Fortran 77或Ada)完成的。
因此,如果您有精通的语言,并且IDE和Apps Hungarian不能帮您,那么请忘记它-显然很多人都有。但是对我来说,这比使用弱语言或动态类型语言的新手程序员更糟糕,我可以使用Apps Hungarian更快地编写更好的代码。
在Joel Spolsky的“使代码看起来错误”中,他解释说每个人都认为匈牙利符号(他称为“系统匈牙利语”)并不是它的真正意图(他称其为Apps Hungarian)。向下滚动到“ 我是匈牙利”标题以查看此讨论。
基本上,系统匈牙利人一文不值。它只是告诉您编译器和/或IDE会告诉您的相同内容。
Apps Hungarian会告诉您该变量的含义,并且实际上可能有用。
Joel的文章很棒,但似乎忽略了一个要点:
匈牙利语使特定的“想法”(种类+标识符名称)在整个代码库中甚至是非常大的代码库中都是唯一的或接近唯一的。
对于代码维护而言,这是巨大的。这意味着您可以使用出色的ol'单行文本搜索(grep,findstr,“在所有文件中查找”)来查找每个提及该“想法”的地方。
当我们拥有知道如何读取代码的IDE时,为什么这么重要?因为他们还不是很擅长。在一个小的代码库中很难看到这一点,但是在一个很大的代码库中却很明显-当在注释,XML文件,Perl脚本以及源代码控制之外的地方(文档,Wiki,Bug数据库)中可能提到“想法”时。
即使在这里,您也必须格外小心-例如,C / C ++宏中的令牌粘贴可能会隐藏标识符的提及。可以使用编码约定来处理这种情况,无论如何,它们往往只影响代码库中的少数标识符。
PS关于使用类型系统与匈牙利语的观点-最好同时使用两者。如果编译器无法为您找到所需的代码,则只需要使用错误的代码来查找错误。在很多情况下,使编译器无法捕获它是不可行的。但是在可行的地方-是的,请改为这样做!
但是,在考虑可行性时,请务必考虑拆分类型的负面影响。例如,在C#中,用非内置类型包装“ int”会产生巨大的后果。因此,在某些情况下(但并非在所有情况下)都有意义。
如果类型是将一个值与另一个值区分开的全部,那么它只能用于将一种类型转换为另一种类型。如果您具有在类型之间转换的相同值,那么您应该在专用于转换的函数中执行此操作。(我看到匈牙利VB6剩菜在它们的所有方法参数上使用字符串,这仅仅是因为它们无法弄清楚如何反序列化JSON对象,或者无法正确理解如何声明或使用可为空的类型。)如果您有两个变量,它们仅以匈牙利前缀,并且它们不是从一个到另一个的转换,因此您需要详细说明使用它们的意图。
我发现匈牙利符号使人们对变量名感到懒惰。他们有一些可以区分的地方,他们认为不需要详细说明它的目的。这通常是在匈牙利标记的代码或现代代码中找到的:sSQL相对于groupSelectSql(或者通常根本不使用sSQL,因为它们应该使用早期开发人员提供的ORM。),sValue与formCollectionValue(或通常没有sValue,因为它们恰好在MVC中,应该使用其模型绑定功能),sType与publishSource等。
它不是可读性。我从任何给定的匈牙利VB6剩余物中看到的sTemp1,sTemp2 ... sTempN比其他所有人的总和还多。
这将借助于数字2,这是错误的。
用大师的话说:
http://www.joelonsoftware.com/articles/Wrong.html
像往常一样有趣的阅读。
提取物:
“有人在某处阅读了Simonyi的论文,在其中他使用了“类型”一词,并认为他的意思是像类一样的类型,就像在类型系统中一样,就像编译器所做的类型检查一样。他没有。他非常仔细地解释。确切地说,他是“类型”一词的意思,但没有帮助。损坏已经造成。”
“但是,Apps Hungarian仍然具有巨大的价值,因为它增加了代码的并置,这使得代码更易于阅读,编写,调试和维护,并且最重要的是,它使错误的代码看起来不正确。”
在阅读Joel On Software之前,请确保您有一些时间。:)
我不认为每个人都对此表示疯狂。在没有静态类型的语言中,它非常有用。当用于提供类型中尚未提供的信息时,我绝对喜欢它。像在C中一样,char * szName表示该变量将引用以null结尾的字符串-在char *中不是隐式的-当然,typedef也将有所帮助。
Joel撰写了一篇很棒的文章,介绍了如何使用匈牙利语来判断变量是否经过HTML编码:
http://www.joelonsoftware.com/articles/Wrong.html
无论如何,当匈牙利人用来传递我已经知道的信息时,我倾向于不喜欢它。
当然,当99%的程序员就某件事达成共识时,就有错了。他们之所以同意这一点,是因为他们大多数人从未正确使用匈牙利符号。
有关详细的论点,请参考我在该主题上发表的一篇博客文章。
http://codingthriller.blogspot.com/2007/11/rediscovering-hungarian-notation.html
匈牙利表示法被滥用,特别是被Microsoft滥用,导致前缀长于变量名,并且显示出它相当僵化的情况,尤其是当您更改类型时(臭名昭著的lparam / wparam,在Win16中具有不同的类型/大小,在Win32中相同) )。
因此,由于这种滥用及其被M $使用,都被认为是无用的。
在我的工作中,我们使用Java编写代码,但是创始人来自MFC世界,因此请使用类似的代码样式(大括号,我喜欢!),大写的是方法名,我习惯了,在类成员(字段,例如m_)前加前缀),s_到静态成员等)。
他们说所有变量都应该有一个前缀来显示其类型(例如,一个BufferedReader名为brData)。这是一个坏主意,因为类型可以更改,但名称不能跟随,或者编码器在使用这些前缀时不一致(我什至看到aBuffer,theProxy等!)。
就我个人而言,我选择了一些我认为有用的前缀,其中最重要的是b作为布尔变量的前缀,因为它们是我唯一允许使用语法if (bVar)
(不使用将某些值自动转换为true或false)的变量。当我用C语言编写代码时,我为malloc分配的变量使用了前缀,以提醒您以后应释放它。等等。
因此,基本上,我总体上不拒绝这种说法,而是选择了适合我需要的内容。
当然,当为某个项目(工作,开源)做出贡献时,我只是使用了约定!