为什么我不应该使用“匈牙利表示法”?
我知道匈牙利语指的是什么 - 将有关变量、参数或类型的信息作为其名称的前缀。 每个人似乎都强烈反对它,尽管在某些情况下这似乎是个好主意。 如果我觉得正在传递有用的信息,为什么我不应该把它放在可以获取的地方呢?
另请参阅:人们是否使用匈牙利命名约定在现实世界中?
I know what Hungarian refers to - giving information about a variable, parameter, or type as a prefix to its name. Everyone seems to be rabidly against it, even though in some cases it seems to be a good idea. If I feel that useful information is being imparted, why shouldn't I put it right there where it's available?
See also: Do people use the Hungarian naming conventions in the real world?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
v 使用 adj 匈牙利语符号 v 使读取 ncode adj 变得困难。
vUsing adjHungarian nnotation vmakes nreading ncode adjdifficult.
大多数人以错误的方式使用匈牙利表示法并得到错误的结果。
阅读 Joel Spolsky 撰写的这篇精彩文章:让错误代码看起来错误。
简而言之,在变量名称前加上变量名的
type
(字符串)(系统匈牙利语)的匈牙利表示法很糟糕,因为它毫无用处。匈牙利表示法,正如其作者所希望的那样,您可以在变量名称前添加其
种类
(使用 Joel 的示例:安全字符串或不安全字符串),所谓的应用程序匈牙利语有其用途并且仍然有价值。Most people use Hungarian notation in a wrong way and are getting wrong results.
Read this excellent article by Joel Spolsky: Making Wrong Code Look Wrong.
In short, Hungarian Notation where you prefix your variable names with their
type
(string) (Systems Hungarian) is bad because it's useless.Hungarian Notation as it was intended by its author where you prefix the variable name with its
kind
(using Joel's example: safe string or unsafe string), so called Apps Hungarian has its uses and is still valuable.乔尔错了,原因如下。
他所说的“应用程序”信息应该在类型系统中进行编码。 您不应该依赖翻转变量名称来确保不会将不安全数据传递给需要安全数据的函数。 您应该将其设置为类型错误,以便不可能这样做。 任何不安全的数据都应该具有标记为不安全的类型,以便它根本无法传递给安全函数。 要从不安全转换为安全,应该需要使用某种清理功能进行处理。
乔尔所说的“种类”的很多东西并不是种类;而是种类。 事实上,它们是类型。
然而,大多数语言缺乏的是一个具有足够表达能力来强制执行这些区别的类型系统。 例如,如果 C 有一种“强 typedef”(其中 typedef 名称具有基本类型的所有操作,但不能转换为它),那么很多这样的问题就会消失。 例如,如果您可以说
strong typedef std::string unsafe_string;
来引入无法转换为 std::string 的新类型unsafe_string
(等等可以参与重载解析等)那么我们就不需要愚蠢的前缀。因此,匈牙利语代表非类型事物的核心主张是错误的。 它用于类型信息。 当然比传统的C类型信息更丰富; 它是对某种语义细节进行编码以指示对象用途的类型信息。 但它仍然是类型信息,正确的解决方案始终是将其编码到类型系统中。 将其编码到类型系统中无疑是获得正确验证和执行规则的最佳方法。 变量名称根本不符合要求。
换句话说,目标不应该是“让错误的代码在开发人员看来是错误的”。 它应该是“让错误的代码在编译器看来是错误的”。
Joel is wrong, and here is why.
That "application" information he's talking about should be encoded in the type system. You should not depend on flipping variable names to make sure you don't pass unsafe data to functions requiring safe data. You should make it a type error, so that it is impossible to do so. Any unsafe data should have a type that is marked unsafe, so that it simply cannot be passed to a safe function. To convert from unsafe to safe should require processing with some kind of a sanitize function.
A lot of the things that Joel talks of as "kinds" are not kinds; they are, in fact, types.
What most languages lack, however, is a type system that's expressive enough to enforce these kind of distinctions. For example, if C had a kind of "strong typedef" (where the typedef name had all the operations of the base type, but was not convertible to it) then a lot of these problems would go away. For example, if you could say,
strong typedef std::string unsafe_string;
to introduce a new typeunsafe_string
that could not be converted to a std::string (and so could participate in overload resolution etc. etc.) then we would not need silly prefixes.So, the central claim that Hungarian is for things that are not types is wrong. It's being used for type information. Richer type information than the traditional C type information, certainly; it's type information that encodes some kind of semantic detail to indicate the purpose of the objects. But it's still type information, and the proper solution has always been to encode it into the type system. Encoding it into the type system is far and away the best way to obtain proper validation and enforcement of the rules. Variables names simply do not cut the mustard.
In other words, the aim should not be "make wrong code look wrong to the developer". It should be "make wrong code look wrong to the compiler".
我认为它使源代码变得非常混乱。
在强类型语言中它也不会给你带来太多好处。 如果您犯了任何形式的类型不匹配的愚蠢行为,编译器会告诉您。
I think it massively clutters up the source code.
It also doesn't gain you much in a strongly typed language. If you do any form of type mismatch tomfoolery, the compiler will tell you about it.
Joel Spolsky 就此写了一篇很好的博客文章。
http://www.joelonsoftware.com/articles/Wrong.html
基本上,当一个像样的 IDE 会告诉你想要的变量类型(如果你不记得了)时,不会让你的代码更难阅读。 另外,如果您将代码划分得足够清楚,您就不必记住三页上声明的变量是什么。
Joel Spolsky wrote a good blog post about this.
http://www.joelonsoftware.com/articles/Wrong.html
Basically it comes down to not making your code harder to read when a decent IDE will tell you want type the variable is if you can't remember. Also, if you make your code compartmentalized enough, you don't have to remember what a variable was declared as three pages up.
在每个变量名称的开头添加神秘字符是不必要的,并且表明变量名称本身的描述性不够。 无论如何,大多数语言在声明时都需要变量类型,因此该信息已经可用。
还有一种情况是,在维护期间,变量类型需要更改。 示例:如果声明为“uint_16 u16foo”的变量需要成为 64 位无符号变量,则会发生以下两种情况之一:
Tacking on cryptic characters at the beginning of each variable name is unnecessary and shows that the variable name by itself isn't descriptive enough. Most languages require the variable type at declaration anyway, so that information is already available.
There's also the situation where, during maintenance, a variable type needs to change. Example: if a variable declared as "uint_16 u16foo" needs to become a 64-bit unsigned, one of two things will happen:
我总是在我的所有项目中使用匈牙利表示法。 当我处理数百个不同的标识符名称时,我发现它确实很有帮助。
例如,当我调用需要字符串的函数时,我可以键入 's' 并点击 control-space,我的 IDE 将准确显示以 's' 为前缀的变量名称。
另一个优点是,当我为无符号整数加上 u 前缀,为有符号整数加上 i 前缀时,我立即看到我在哪里以潜在危险的方式混合了有符号和无符号。
我不记得在一个巨大的 75000 行代码库中,由于将局部变量命名为与该类的现有成员变量相同而导致错误(由我和其他人)的次数。 从那时起,我总是在会员前面加上“m_”,
这是品味和经验的问题。 在尝试之前不要敲它。
I always use Hungarian notation for all my projects. I find it really helpful when I'm dealing with 100s of different identifier names.
For example, when I call a function requiring a string I can type 's' and hit control-space and my IDE will show me exactly the variable names prefixed with 's' .
Another advantage, when I prefix u for unsigned and i for signed ints, I immediately see where I am mixing signed and unsigned in potentially dangerous ways.
I cannot remember the number of times when in a huge 75000 line codebase, bugs were caused (by me and others too) due to naming local variables the same as existing member variables of that class. Since then, I always prefix members with 'm_'
Its a question of taste and experience. Don't knock it until you've tried it.
您忘记了包含此信息的首要原因。 这与你程序员无关。 这与你离开公司两三年后必须读这些东西的人有关。
是的,IDE 会快速为您识别类型。 然而,当您阅读一些长批次的“业务规则”代码时,最好不必在每个变量上暂停来找出它是什么类型。 当我看到诸如 strUserID、intProduct 或 guiProductID 之类的内容时,它会让“加速”时间变得更容易。
我同意 MS 在某些命名约定上走得太远了——我将其归为“太多好事”。
命名约定是件好事,只要你遵守它们。 我已经浏览了足够多的旧代码,这让我不断地回头查看许多名称相似的变量的定义,以至于我推动了“驼峰式大小写”(因为它在之前的工作中被称为)。 现在,我的工作有数千行完全未注释的 VBScript 经典 ASP 代码,试图解决这些问题是一场噩梦。
You're forgetting the number one reason to include this information. It has nothing to do with you, the programmer. It has everything to do with the person coming down the road 2 or 3 years after you leave the company who has to read that stuff.
Yes, an IDE will quickly identify types for you. However, when you're reading through some long batches of 'business rules' code, it's nice to not have to pause on each variable to find out what type it is. When I see things like strUserID, intProduct or guiProductID, it makes for much easier 'ramp up' time.
I agree that MS went way too far with some of their naming conventions - I categorize that in the "too much of a good thing" pile.
Naming conventions are good things, provided you stick to them. I've gone through enough old code that had me constantly going back to look at the definitions for so many similarly-named variables that I push "camel casing" (as it was called at a previous job). Right now I'm on a job that has many thousand of lines of completely uncommented classic ASP code with VBScript and it's a nightmare trying to figure things out.
匈牙利表示法仅在没有用户定义类型的语言中才有意义。 在现代函数式或面向对象语言中,您可以将有关值“种类”的信息编码到数据类型或类中,而不是编码到变量名称中。
有几个答案参考了 Joels 文章。 但请注意,他的示例是用 VBScript 编写的,它不支持用户定义的类(至少在很长一段时间内)。 在具有用户定义类型的语言中,您可以通过创建 HtmlEncodedString 类型来解决相同的问题,然后让 Write 方法仅接受该类型。 在静态类型语言中,编译器将捕获任何编码错误,在动态类型语言中,您将得到运行时异常 - 但无论如何,您都可以防止写入未编码的字符串。 匈牙利符号只是将程序员变成了人类类型检查员,而这种工作通常由软件更好地处理。
Joel 区分了“systemsungarian”和“appshungarian”,其中“systemshungarian”编码 int、float 等内置类型,“appshungarian”编码“kinds”,这是更高级别的元信息关于机器类型之外的变量,在面向对象或现代函数式语言中,您可以创建用户定义的类型,因此在这个意义上,类型和“种类”之间没有区别 - 两者都可以由类型系统表示 - 和“应用程序”匈牙利语和“系统”匈牙利语一样多余。
因此,回答你的问题:匈牙利语仅在不安全的弱类型语言中有用,例如将浮点值分配给 int 变量将使系统崩溃。 匈牙利表示法是在六十年代专门发明的,用于 BCPL,这是一种相当低级的语言,根本不做任何类型检查。 我认为当今通用的任何语言都没有这个问题,但这种符号作为一种货物崇拜编程而存在。
如果您使用没有用户定义类型的语言(例如旧版 VBScript 或早期版本的 VB),匈牙利语应用程序将有意义。 也许还有 Perl 和 PHP 的早期版本。 同样,在现代语言中使用它纯粹是对货物的崇拜。
在任何其他语言中,匈牙利语都是丑陋的、多余的和脆弱的。 它重复了类型系统中已知的信息,并且您不应该重复自己。 使用变量的描述性名称来描述该类型的特定实例的意图。 使用类型系统对变量的“种类”或“类”的不变量和元信息进行编码 - 即。 类型。
Joels 文章的一般观点 - 让错误的代码看起来错误 - 是一个非常好的原则。 然而,更好的防止错误的方法是——在可能的情况下——让编译器自动检测到错误的代码。
Hungarian notation only makes sense in languages without user-defined types. In a modern functional or OO-language, you would encode information about the "kind" of value into the datatype or class rather than into the variable name.
Several answers reference Joels article. Note however that his example is in VBScript, which didn't support user-defined classes (for a long time at least). In a language with user-defined types you would solve the same problem by creating a HtmlEncodedString-type and then let the Write method accept only that. In a statically typed language, the compiler will catch any encoding-errors, in a dynamically typed you would get a runtime exception - but in any case you are protected against writing unencoded strings. Hungarian notations just turns the programmer into a human type-checker, with is the kind of job that is typically better handled by software.
Joel distinguishes between "systems hungarian" and "apps hungarian", where "systems hungarian" encodes the built-in types like int, float and so on, and "apps hungarian" encodes "kinds", which is higher-level meta-info about variable beyound the machine type, In a OO or modern functional language you can create user-defined types, so there is no distinction between type and "kind" in this sense - both can be represented by the type system - and "apps" hungarian is just as redundant as "systems" hungarian.
So to answer your question: Systems hungarian would only be useful in a unsafe, weakly typed language where e.g. assigning a float value to an int variable will crash the system. Hungarian notation was specifically invented in the sixties for use in BCPL, a pretty low-level language which didn't do any type checking at all. I dont think any language in general use today have this problem, but the notation lived on as a kind of cargo cult programming.
Apps hungarian will make sense if you are working with a language without user defined types, like legacy VBScript or early versions of VB. Perhaps also early versions of Perl and PHP. Again, using it in a modern languge is pure cargo cult.
In any other language, hungarian is just ugly, redundant and fragile. It repeats information already known from the type system, and you should not repeat yourself. Use a descriptive name for the variable that describes the intent of this specific instance of the type. Use the type system to encode invariants and meta info about "kinds" or "classes" of variables - ie. types.
The general point of Joels article - to have wrong code look wrong - is a very good principle. However an even better protection against bugs is to - when at all possible - have wrong code to be detected automatically by the compiler.
揭穿匈牙利表示法的好处
如果类型是区分一个值与另一个值的全部,那么它只能用于一种类型到另一种类型的转换。 如果您在类型之间转换的值相同,那么您很可能应该在专用于转换的函数中执行此操作。 (我见过匈牙利的 VB6 剩菜在其所有方法参数上使用字符串,只是因为他们无法弄清楚如何反序列化 JSON 对象,或正确理解如何声明或使用可空类型。)如果您有两个变量仅通过匈牙利语前缀区分,并且它们不是从一个到另一个的转换,那么您需要用它们详细说明您的意图。
我发现匈牙利表示法使人们在变量名上变得懒惰。 他们有一些可以区分的东西,而且他们觉得没有必要详细说明其目的。 这就是您通常会在匈牙利符号代码与现代代码中找到的内容:sSQL 与 groupSelectSql(或者通常根本没有 sSQL,因为它们应该使用早期开发人员放入的 ORM。 )、sValue 与 formCollectionValue(或者通常没有 sValue,因为它们恰好在 MVC 中并且应该使用其模型绑定功能)、sType 与publishSource 等。
它不具有可读性。 我从任何给定的匈牙利 VB6 剩余物中看到的 sTemp1、sTemp2...sTempN 比其他所有人的总和还要多。
这是由于数字 2,它是错误的。
Debunking the benefits of Hungarian Notation
If the type is all that distinguishes the one value from another, then it can only be for the conversion of one type to another. If you have the same value that is being converted between types, chances are you should be doing this in a function dedicated to conversion. (I have seen hungarianed VB6 leftovers use strings on all of their method parameters simply because they could not figure out how to deserialize a JSON object, or properly comprehend how to declare or use nullable types.) If you have two variables distinguished only by the Hungarian prefix, and they are not a conversion from one to the other, then you need to elaborate on your intention with them.
I have found that Hungarian notation makes people lazy with their variable names. They have something to distinguish it by, and they feel no need to elaborate to its purpose. This is what you will typically find in Hungarian notated code vs. modern: sSQL vs. groupSelectSql (or usually no sSQL at all because they are supposed to be using the ORM that was put in by earlier developers.), sValue vs. formCollectionValue (or usually no sValue either, because they happen to be in MVC and should be using its model binding features), sType vs. publishSource, etc.
It can't be readability. I see more sTemp1, sTemp2... sTempN from any given hungarianed VB6 leftover than everybody else combined.
This would be by virtue of number 2, which is false.
用大师的话来说:
http://www.joelonsoftware.com/articles/Wrong.html
像往常一样,这是一本有趣的读物。
摘录:
“有人在某个地方读了西蒙尼的论文,其中他使用了“类型”这个词,并认为他的意思是类型,就像类,就像类型系统中的类型,就像编译器所做的类型检查一样。他没有。他解释说非常仔细地准确地了解了他所说的“类型”这个词的含义,但这并没有带来任何帮助。”
“但是 Apps Hungarian 仍然具有巨大的价值,因为它增加了代码的搭配,使代码更易于阅读、编写、调试和维护,最重要的是,它使错误的代码看起来是错误的。”
请确保您在阅读 Joel On Software 之前有一些时间。 :)
In the words of the master:
http://www.joelonsoftware.com/articles/Wrong.html
An interesting reading, as usual.
Extracts:
"Somebody, somewhere, read Simonyi’s paper, where he used the word “type,” and thought he meant type, like class, like in a type system, like the type checking that the compiler does. He did not. He explained very carefully exactly what he meant by the word “type,” but it didn’t help. The damage was done."
"But there’s still a tremendous amount of value to Apps Hungarian, in that it increases collocation in code, which makes the code easier to read, write, debug, and maintain, and, most importantly, it makes wrong code look wrong."
Make sure you have some time before reading Joel On Software. :)
有几个原因:
Several reasons:
我不认为每个人都强烈反对它。 在没有静态类型的语言中,它非常有用。 当它用于提供类型中尚未包含的信息时,我绝对更喜欢它。 与 C 中一样,char * szName 表示该变量将引用以 null 结尾的字符串——这在 char* 中不是隐式的——当然,typedef 也会有所帮助。
Joel 有一篇很棒的文章,介绍了如何使用匈牙利语来判断变量是否是 HTML 编码的:
http:// /www.joelonsoftware.com/articles/Wrong.html
无论如何,当匈牙利语被用来传递我已经知道的信息时,我倾向于不喜欢它。
I don't think everyone is rabidly against it. In languages without static types, it's pretty useful. I definitely prefer it when it's used to give information that is not already in the type. Like in C, char * szName says that the variable will refer to a null terminated string -- that's not implicit in char* -- of course, a typedef would also help.
Joel had a great article on using hungarian to tell if a variable was HTML encoded or not:
http://www.joelonsoftware.com/articles/Wrong.html
Anyway, I tend to dislike Hungarian when it's used to impart information I already know.
当然,当 99% 的程序员都同意某件事时,那就有问题了。 他们之所以在这里达成一致,是因为他们中的大多数人从未正确使用过匈牙利表示法。
对于详细的论证,我建议您参阅我就该主题发表的一篇博客文章。
http://codingthriller.blogspot.com/2007/11/rediscovering-匈牙利符号.html
Of course when 99% of programmers agree on something, there is something wrong. The reason they agree here is because most of them have never used Hungarian notation correctly.
For a detailed argument, I refer you to a blog post I have made on the subject.
http://codingthriller.blogspot.com/2007/11/rediscovering-hungarian-notation.html
我几乎在匈牙利表示法发明时就开始编码,当我第一次被迫在一个我讨厌它的项目中使用它时。
一段时间后,我意识到,如果做得正确,它确实有帮助,现在我很喜欢它。
但就像所有美好的事情一样,它必须被学习和理解,并且正确地做到这一点需要时间。
I started coding pretty much the about the time Hungarian notation was invented and the first time I was forced to use it on a project I hated it.
After a while I realised that when it was done properly it did actually help and these days I love it.
But like all things good, it has to be learnt and understood and to do it properly takes time.
匈牙利表示法被滥用,特别是被 Microsoft 滥用,导致前缀比变量名长,并且显示它相当严格,特别是当您更改类型时(臭名昭著的 lparam/wparam,在 Win16 中具有不同的类型/大小,在 Win32 中相同) )。
因此,由于这种滥用以及 M$ 对它的使用,它被认为是无用的。
在我的工作中,我们用Java编写代码,但创始人来自MFC世界,所以使用类似的代码风格(对齐的大括号,我喜欢这个!,方法名称大写,我已经习惯了,像m_这样的前缀给类成员(字段) )、s_ 到静态成员等)。
他们说所有变量都应该有一个显示其类型的前缀(例如 BufferedReader 名为 brData)。 这被证明是一个坏主意,因为类型可以改变,但名称不跟随,或者编码者在使用这些前缀时不一致(我什至看到 aBuffer、theProxy 等!)。
就我个人而言,我选择了一些我认为有用的前缀,最重要的是 b 作为布尔变量的前缀,因为它们是唯一允许像
if (bVar)
这样的语法的前缀(不使用 autocast某些值为 true 或 false)。当我用 C 编写代码时,我对用 malloc 分配的变量使用了前缀,以提醒它应该稍后释放。 等等。
所以,基本上,我不会整体上拒绝这种表示法,而是采用了看起来适合我的需求的东西。
当然,当为某些项目(工作、开源)做出贡献时,我只是使用适当的约定!
The Hungarian notation was abused, particularly by Microsoft, leading to prefixes longer than the variable name, and showing it is quite rigid, particularly when you change the types (the infamous lparam/wparam, of different type/size in Win16, identical in Win32).
Thus, both due to this abuse, and its use by M$, it was put down as useless.
At my work, we code in Java, but the founder cames from MFC world, so use similar code style (aligned braces, I like this!, capitals to method names, I am used to that, prefix like m_ to class members (fields), s_ to static members, etc.).
And they said all variables should have a prefix showing its type (eg. a BufferedReader is named brData). Which shown as being a bad idea, as the types can change but the names doesn't follow, or coders are not consistent in the use of these prefixes (I even see aBuffer, theProxy, etc.!).
Personally, I chose for a few prefixes that I find useful, the most important being b to prefix boolean variables, as they are the only ones where I allow syntax like
if (bVar)
(no use of autocast of some values to true or false).When I coded in C, I used a prefix for variables allocated with malloc, as a reminder it should be freed later. Etc.
So, basically, I don't reject this notation as a whole, but took what seems fitting for my needs.
And of course, when contributing to some project (work, open source), I just use the conventions in place!
匈牙利表示法在没有编译时类型检查的语言中很有用,因为它可以让开发人员快速提醒自己如何使用特定变量。 它对性能或行为没有任何作用。 它应该提高代码的可读性,主要是品味和编码风格的问题。 正是因为这个原因,它受到了许多开发人员的批评——并不是每个人的大脑都有相同的线路。
对于编译时类型检查语言来说,它几乎没有用——向上滚动几行应该会显示声明和类型。 如果全局变量或代码块跨越多个屏幕,则会遇到严重的设计和可重用性问题。 因此,批评之一是匈牙利表示法允许开发人员进行糟糕的设计并轻松逃脱惩罚。 这大概也是仇恨的原因之一吧。
另一方面,在某些情况下,甚至编译时类型检查语言也会受益于匈牙利表示法——win32 API 中的 void 指针或 HANDLE。 这些混淆了实际的数据类型,并且在那里使用匈牙利表示法可能是有好处的。 然而,如果可以在构建时知道数据的类型,为什么不使用适当的数据类型呢?
一般来说,没有什么理由不使用匈牙利表示法。 这是一个喜好、政策和编码风格的问题。
Hungarian Notation can be useful in languages without compile-time type checking, as it would allow developer to quickly remind herself of how the particular variable is used. It does nothing for performance or behavior. It is supposed to improve code readability and is mostly a matter a taste and coding style. For this very reason it is criticized by many developers -- not everybody has the same wiring in the brain.
For the compile-time type-checking languages it is mostly useless -- scrolling up a few lines should reveal the declaration and thus type. If you global variables or your code block spans for much more than one screen, you have grave design and reusability issues. Thus one of the criticisms is that Hungarian Notation allows developers to have bad design and easily get away with it. This is probably one of the reasons for hatered.
On the other hand, there can be cases where even compile-time type-checking languages would benefit from Hungarian Notation -- void pointers or HANDLE's in win32 API. These obfuscates the actual data type, and there might be a merit to use Hungarian Notation there. Yet, if one can know the type of data at build time, why not to use the appropriate data type.
In general, there are no hard reasons not to use Hungarian Notation. It is a matter of likes, policies, and coding style.
作为一名 Python 程序员,匈牙利表示法很快就会崩溃。 在Python中,我不关心某个东西是否是一个字符串 - 我关心它是否可以表现得像一个字符串(即如果它有一个
___str___()< /code> 返回字符串的方法)。
例如,假设我们有 foo 作为整数,12
匈牙利表示法告诉我们应该称其为 iFoo 或其他名称,以表示它是一个整数,以便稍后我们知道它是什么。 除了 Python 之外,这不起作用,或者更确切地说,它没有意义。 在Python中,我在使用时决定我想要什么类型。 我想要一根绳子吗? 好吧,如果我这样做:
请注意
%s
- 字符串。 Foo 不是字符串,但%
运算符将调用foo.___str___()
并使用结果(假设它存在)。foo
仍然是一个整数,但是如果我们想要一个字符串,我们就把它当作一个字符串。 如果我们想要一个浮点数,那么我们就把它当作一个浮点数。 在像Python这样的动态类型语言中,匈牙利表示法是没有意义的,因为在你使用它之前,它是什么类型并不重要,如果你需要一个特定的类型,那么只需确保将它转换为该类型(例如float(foo)
) 当你使用它时。请注意,像 PHP 这样的动态语言没有这个好处 - PHP 试图根据一组几乎没有人记住的晦涩规则在后台做“正确的事情”,这通常会导致意外的灾难性混乱。 在这种情况下,某种命名机制(例如
$files_count
或$file_name
)可能会很方便。在我看来,匈牙利表示法就像水蛭。 也许在过去它们很有用,或者至少看起来很有用,但现在只是大量额外的输入,但没有多大好处。
As a Python programmer, Hungarian Notation falls apart pretty fast. In Python, I don't care if something is a string - I care if it can act like a string (i.e. if it has a
___str___()
method which returns a string).For example, let's say we have foo as an integer, 12
Hungarian notation tells us that we should call that iFoo or something, to denote it's an integer, so that later on, we know what it is. Except in Python, that doesn't work, or rather, it doesn't make sense. In Python, I decide what type I want when I use it. Do I want a string? well if I do something like this:
Note the
%s
- string. Foo isn't a string, but the%
operator will callfoo.___str___()
and use the result (assuming it exists).foo
is still an integer, but we treat it as a string if we want a string. If we want a float, then we treat it as a float. In dynamically typed languages like Python, Hungarian Notation is pointless, because it doesn't matter what type something is until you use it, and if you need a specific type, then just make sure to cast it to that type (e.g.float(foo)
) when you use it.Note that dynamic languages like PHP don't have this benefit - PHP tries to do 'the right thing' in the background based on an obscure set of rules that almost no one has memorized, which often results in catastrophic messes unexpectedly. In this case, some sort of naming mechanism, like
$files_count
or$file_name
, can be handy.In my view, Hungarian Notation is like leeches. Maybe in the past they were useful, or at least they seemed useful, but nowadays it's just a lot of extra typing for not a lot of benefit.
IDE 应该传递有用的信息。 当 IDE 不太先进时,匈牙利语可能已经产生了某种意义(不是很多,但某种意义)。
The IDE should impart that useful information. Hungarian might have made some sort (not a whole lot, but some sort) of sense when IDE's were much less advanced.
Apps Hungarian 对我来说是希腊语——以一种很好的方式
作为一名工程师,而不是程序员,我立即阅读了 Joel 的关于 Apps Hungarian 优点的文章: "让错误的代码看起来是错误的"。 我喜欢 Apps Hungarian,因为它模仿工程、科学和数学如何使用下标和上标符号(例如希腊字母、数学运算符等)表示方程和公式。 以牛顿万有引力定律为例:首先采用标准数学符号,并且然后在 Apps Hungarian 伪代码中:
在数学符号中,最突出的符号那些表示存储在变量中的信息的种类:力、质量、位置矢量等。下标起着次要作用来澄清:什么的位置? 这正是 Apps Hungarian 正在做的事情; 它首先告诉您变量中存储的事物的种类,然后再了解细节——最接近的代码可以得到数学符号。
显然,强类型可以解决 Joel 文章中的安全与不安全字符串示例,但您不会为位置和速度向量定义单独的类型; 两者都是大小为 3 的双数组,您可能对一个数组执行的任何操作都可能适用于另一个数组。 此外,连接位置和速度(以生成状态向量)或获取它们的点积是非常有意义的,但可能不会将它们相加。 打字如何允许前两个并禁止第二个,以及这样的系统如何扩展到您可能想要保护的每个可能的操作? 除非您愿意在打字系统中编码所有数学和物理知识。
最重要的是,许多工程都是用弱类型高级语言(如 Matlab)或旧语言(如 Fortran 77 或 Ada)完成的。
因此,如果您有一种奇特的语言,而 IDE 和 Apps Hungarian 无法帮助您,那么就忘记它吧——很多人显然都有。 但对我来说,比使用弱类型或动态类型语言的新手程序员更糟糕的是,使用 Apps Hungarian 可以比不使用 Apps Hungarian 更快地编写更好的代码。
Apps Hungarian is Greek to me--in a good way
As an engineer, not a programmer, I immediately took to Joel's article on the merits of Apps Hungarian: "Making Wrong Code Look Wrong". I like Apps Hungarian because it mimics how engineering, science, and mathematics represent equations and formulas using sub- and super-scripted symbols (like Greek letters, mathematical operators, etc.). Take a particular example of Newton's Law of Universal Gravity: first in standard mathematical notation, and then in Apps Hungarian pseudo-code:
In the mathematical notation, the most prominent symbols are those representing the kind of information stored in the variable: force, mass, position vector, etc. The subscripts play second fiddle to clarify: position of what? This is exactly what Apps Hungarian is doing; it's telling you the kind of thing stored in the variable first and then getting into specifics--about the closest code can get to mathematical notation.
Clearly strong typing can resolve the safe vs. unsafe string example from Joel's essay, but you wouldn't define separate types for position and velocity vectors; both are double arrays of size three and anything you're likely to do to one might apply to the other. Furthermore, it make perfect sense to concatenate position and velocity (to make a state vector) or take their dot product, but probably not to add them. How would typing allow the first two and prohibit the second, and how would such a system extend to every possible operation you might want to protect? Unless you were willing to encode all of math and physics in your typing system.
On top of all that, lots of engineering is done in weakly typed high-level languages like Matlab, or old ones like Fortran 77 or Ada.
So if you have a fancy language and IDE and Apps Hungarian doesn't help you then forget it--lots of folks apparently have. But for me, a worse than a novice programmer who is working in weakly or dynamically typed languages, I can write better code faster with Apps Hungarian than without.
大多数现代 IDE 都非常冗余和无用,它们在使类型变得明显方面做得很好。
另外——对我来说——看到 intI、strUserName 等只是很烦人。:)
It's incredibly redundant and useless is most modern IDEs, where they do a good job of making the type apparent.
Plus -- to me -- it's just annoying to see intI, strUserName, etc. :)
那么谁在乎别人怎么想呢? 如果您发现它有用,请使用该符号。
Then who cares what anybody else thinks? If you find it useful, then use the notation.
根据我的经验,这很糟糕,因为:
1 - 如果您需要更改变量的类型(即,如果您需要将 32 位整数扩展为 64 位整数),那么您会破坏所有代码;
2 - 这是无用的信息,因为类型要么已经在声明中,要么您使用动态语言,其中实际类型一开始就不应该那么重要。
此外,对于接受泛型编程(即在编写函数时某些变量的类型不确定的函数)或使用动态类型系统(即当类型在编译时甚至不确定时)的语言,您将如何命名您的函数?变量? 大多数现代语言都支持其中一种,即使形式有限。
Im my experience, it is bad because:
1 - then you break all the code if you need to change the type of a variable (i.e. if you need to extend a 32 bits integer to a 64 bits integer);
2 - this is useless information as the type is either already in the declaration or you use a dynamic language where the actual type should not be so important in the first place.
Moreover, with a language accepting generic programming (i.e. functions where the type of some variables is not determine when you write the function) or with dynamic typing system (i.e. when the type is not even determine at compile time), how would you name your variables? And most modern languages support one or the other, even if in a restricted form.
在 Joel Spolsky 的《让错误代码看起来错误》 中,他解释了每个人都认为的匈牙利表示法(他称之为匈牙利系统)并不是它真正的意图(他称之为匈牙利应用程序)。 向下滚动到我是匈牙利标题即可查看此讨论。
基本上,Systems Hungarian 毫无价值。 它只是告诉你你的编译器和/或 IDE 会告诉你的同样的事情。
Apps Hungarian 会告诉您该变量的含义,并且实际上很有用。
In Joel Spolsky's Making Wrong Code Look Wrong he explains that what everybody thinks of as Hungarian Notation (which he calls Systems Hungarian) is not what was it was really intended to be (what he calls Apps Hungarian). Scroll down to the I’m Hungary heading to see this discussion.
Basically, Systems Hungarian is worthless. It just tells you the same thing your compiler and/or IDE will tell you.
Apps Hungarian tells you what the variable is supposed to mean, and can actually be useful.
我一直认为在正确的位置添加一两个前缀不会有什么坏处。 我想如果我可以传递一些有用的东西,比如“嘿,这是一个界面,不要指望特定的行为”,就像在 IEnumerable 中一样,我应该这样做。 注释比一两个字符的符号更能让事情变得混乱。
I've always thought that a prefix or two in the right place wouldn't hurt. I think if I can impart something useful, like "Hey this is an interface, don't count on specific behaviour" right there, as in IEnumerable, I oughtta do it. Comment can clutter things up much more than just a one or two character symbol.
如果控件列表显示在 IDE 中按字母顺序排列的下拉列表中,那么对于在表单上命名控件(btnOK、txtLastName 等),这是一个有用的约定。
It's a useful convention for naming controls on a form (btnOK, txtLastName etc.), if the list of controls shows up in an alphabetized pull-down list in your IDE.
我倾向于仅对 ASP.NET 服务器控件使用匈牙利表示法,否则我发现很难确定表单上的控件是什么。
看看这个代码片段:
如果有人可以展示一种更好的方法来获得一组没有匈牙利语的控件名称,我会很想转向它。
I tend to use Hungarian Notation with ASP.NET server controls only, otherwise I find it too hard to work out what controls are what on the form.
Take this code snippet:
If someone can show a better way of having that set of control names without Hungarian I'd be tempted to move to it.
乔尔的文章很棒,但似乎忽略了一个要点:
匈牙利语使特定的“想法”(种类+标识符名称)独一无二,
或者在整个代码库中几乎是唯一的 - 即使是非常大的代码库。
这对于代码维护来说是巨大的。
这意味着您可以使用良好的单行文本搜索
(grep, findstr, '在所有文件中查找') 查找每个提到该“想法”的内容。
当我们拥有知道如何读取代码的 IDE 时,为什么这一点很重要?
因为他们还不太擅长。 这在小型代码库中很难看到,
但在大的情况下很明显 - 当评论中可能提到“想法”时,
XML 文件、Perl 脚本以及源代码控制之外的位置(文档、wiki、
错误数据库)。
即使在这里,您也必须小心一点 - 例如 C/C++ 宏中的标记粘贴
可以隐藏标识符的提及。 此类情况可以使用以下方法处理
编码约定,无论如何,它们往往只影响少数标识符
代码库。
PS 关于使用类型系统与匈牙利语的问题 - 最好同时使用两者。
如果编译器无法为您捕获错误的代码,您只需要看起来错误即可。 在很多情况下,让编译器捕获它是不可行的。 但如果可行的话 - 是的,请这样做!
不过,在考虑可行性时,请务必考虑拆分类型的负面影响。 例如,在 C# 中,用非内置类型包装“int”会产生巨大的后果。 因此,这在某些情况下是有意义的,但并非在所有情况下都有意义。
Joel's article is great, but it seems to omit one major point:
Hungarian makes a particular 'idea' (kind + identifier name) unique,
or near-unique, across the codebase - even a very large codebase.
That's huge for code maintenance.
It means you can use good ol' single-line text search
(grep, findstr, 'find in all files') to find EVERY mention of that 'idea'.
Why is that important when we have IDE's that know how to read code?
Because they're not very good at it yet. This is hard to see in a small codebase,
but obvious in a large one - when the 'idea' might be mentioned in comments,
XML files, Perl scripts, and also in places outside source control (documents, wikis,
bug databases).
You do have to be a little careful even here - e.g. token-pasting in C/C++ macros
can hide mentions of the identifier. Such cases can be dealt with using
coding conventions, and anyway they tend to affect only a minority of the identifiers in the
codebase.
P.S. To the point about using the type system vs. Hungarian - it's best to use both.
You only need wrong code to look wrong if the compiler won't catch it for you. There are plenty of cases where it is infeasible to make the compiler catch it. But where it's feasible - yes, please do that instead!
When considering feasibility, though, do consider the negative effects of splitting up types. e.g. in C#, wrapping 'int' with a non-built-in type has huge consequences. So it makes sense in some situations, but not in all of them.
如今,范围不是比类型更重要吗?例如,
使用重构旧代码的现代技术,由于更改了符号的类型而搜索和替换符号是乏味的,编译器会捕获类型更改,但通常不会捕获范围的错误使用,合理的命名约定在这里有帮助。
Isn't scope more important than type these days, e.g.
With modern techniques of refactoring old code, search and replace of a symbol because you changed its type is tedious, the compiler will catch type changes, but often will not catch incorrect use of scope, sensible naming conventions help here.
您没有理由不正确使用匈牙利表示法。 它不受欢迎的原因是长期以来对匈牙利表示法的误用(尤其是在 Windows API 中)的强烈反对。
在过去的糟糕日子里,在 DOS 出现类似 IDE 的东西之前(很可能你没有足够的可用内存来在 Windows 下运行编译器,所以你的开发是在 DOS 中完成的),你没有得到任何帮助将鼠标悬停在变量名称上。 (假设您有鼠标。)您需要处理的是事件回调函数,其中所有内容都以 16 位 int (WORD) 或 32 位 int (LONG WORD) 形式传递给您。 然后,您必须将这些参数转换为给定事件类型的适当类型。 实际上,大部分 API 实际上是无类型的。
结果是一个具有如下参数名称的 API:
请注意,名称 wParam 和 lParam 虽然相当糟糕,但实际上并不比命名它们 param1 和 param2 更糟糕。
更糟糕的是,Window 3.0/3.1 有两种类型的指针:近指针和远指针。 例如,内存管理函数 LocalLock 的返回值是 PVOID,但 GlobalLock 的返回值是 LPVOID(长字符为“L”)。 然后,这个可怕的符号得到了扩展,以便 long p 指针字符串带有前缀 lp,以将其与简单地 malloc 的字符串区分开来。 'd。
此类事情遭到强烈反对也就不足为奇了。
There is no reason why you should not make correct use of Hungarian notation. It's unpopularity is due to a long-running back-lash against the mis-use of Hungarian notation, especially in the Windows APIs.
In the bad-old days, before anything resembling an IDE existed for DOS (odds are you didn't have enough free memory to run the compiler under Windows, so your development was done in DOS), you didn't get any help from hovering your mouse over a variable name. (Assuming you had a mouse.) What did you did have to deal with were event callback functions in which everything was passed to you as either a 16-bit int (WORD) or 32-bit int (LONG WORD). You then had to cast those parameter to the appropriate types for the given event type. In effect, much of the API was virtually type-less.
The result, an API with parameter names like these:
Note that the names wParam and lParam, although pretty awful, aren't really any worse than naming them param1 and param2.
To make matters worse, Window 3.0/3.1 had two types of pointers, near and far. So, for example, the return value from memory management function LocalLock was a PVOID, but the return value from GlobalLock was an LPVOID (with the 'L' for long). That awful notation then got extended so that a long pointer string was prefixed lp, to distinguish it from a string that had simply been malloc'd.
It's no surprise that there was a backlash against this sort of thing.