“系统匈牙利语”表示法仍然有用吗?[关闭]


23

我在论坛上进行了搜索,但是找不到为什么应避免使用它的答案,而只是为什么它不是灵丹妙药。所以我不认为这个问题是重复的。

是否有有效的理由为什么我应该取消学习惯用的系统匈牙利语?

到目前为止,我发现使用它具有以下好处:

  • 一致的变量命名
  • 您无需搜索即可看到类型(智能在半数时间中已失效/已建立索引,因此这仍然是一个合理的原因)
  • 语义仍然可以包含在名称的第二部分中

以及以下缺点:

  • 惹恼了一些人(不知道为什么)
  • 如果更改了类型,则该类型可能与变量的名称不匹配(我不认为这是正当的理由,类型很少更改,并且您拥有“全部重命名”)

所以为什么:

vector<string> vecCityNames;
wstring strCity = L"abc";
//more code here
vecCityNames.push_back(strCity);

差于:

vector<string> cityNames;
wstring city = L"abc";
//more code here
cityNames.push_back(city);//Are we pushing back int on a queue? Float on a stack? Something else?

4
如果intellisense无效,则您的代码无效。如果无效,为什么要假定变量名正确?
Bubblewrap

6
@Bubblewrap:即使在有效代码上,大多数智能感知实现有时也会停顿3秒。有时,即使代码可以编译和链接,它们也根本无法工作。我们正在谈论大小合理的项目。
编码器

9
对于您一致的论点来说,它不vectCityNames应该vectStringCityNames太重要,而且这个“问题”比什么都重要,您已经下定了决心,应该关闭它。

8
您认为什么是“有效”原因?
亚当李尔

15
我不认为您的第二个示例在您的评论表明的方式上令人困惑。的意思cityNames.push_back(city)很清楚。这是城市名称的列表,您要添加一个。
克里斯·伯特·布朗

Answers:


62

我曾经使用它(很多年前),现在不再使用。主要原因是它在OO语言中具有强类型(C ++,Java)是多余的,而我恰好使用了我的大部分职业。在这些语言中,如果我很好地定义了类型,则编译器可以并且将为我强制执行类型安全性。因此,任何命名前缀都只会使名称变长,从而使名称难以阅读和搜索。

在任何写得好的OO程序中,大多数变量是用户定义的类型(对它们的引用)。如果为它们加上相同的常规标记(例如o“ object”),则不会从中获得任何好处,而只会带来弊端。但是,如果给它们加上特定于类型的标签作为前缀,就会陷入迷宫,试图为通常具有相似名称*的一千种不同类型查找不同的缩写,并记住在类型或其名称更改时将它们全部更改(即在维护良好的程序中一点都不罕见)。

当然,这不适用于非OO语言,也可能不适用于弱类型和/或动态类型的语言(除C外,我没有使用这些语言的经验)。没有可用的IntelliSense(或其本地等效版本)的编辑器/ IDE都不佳。这只是我的2美分。因此,如果匈牙利符号适合您的团队和项目,那就去做吧。重要的是在项目开始之前就此达成共识(以及通常的一致编码风格),并始终保持一致。

* 从我们目前的项目只是一个简短的清单:我们有ChargeChargeBreakdownChargeCalculatorChargeDAOChargeDTOChargeLineHelperChargeMapsChargePairChargeType,等等。此外,我们在项目中也有Contracts,Countries,Checkouts,Checkins ...,而这只是字母C,OP甚至可能不会将其称为“合理大小”。


免责声明:我实际上是匈牙利人,所以我相信我可以在这个问题上拥有权威;-)


“强类型”-如果C ++具有真正强大的类型系统,那么您不必将类型嵌入变量名中。
Michael Burge

19
@MichaelBurge:这就是重点。不用了 因为有。
DeadMG

8
关于用户定义类型的观点为+1。使用命名为iPosfAmount可以允许使用的变量,但是请尝试在代码库上工作,在该代码库中,为每个对象变量分配一个冗余的六字母前缀,仅通知您它是“结构的指针”。

2
对于GUI而言,我将是一个例外,在GUI中,除了它的值之外,还需要为每个控件存储一个句柄,因此text和hText不必为输入框考虑其他名称。在手柄只是int而不是特殊类型的系统上尤其重要。
马丁·贝克特

1
我认为Java应该推荐使用匈牙利表示法的一个主要地方是区分对可能被突变但从未共享的实例的引用(例如,char[]由a持有StringBuilder)和对不能被突变的实例的引用之间的区别,但是可能会与不会改变它们的事物共享(例如,char[]由持有的String,可能会在多个String实例之间共享)。这两个字段的类型相同char[],但是它们所保存的内容却大不相同。许多与可变性相关的错误源于...
超级猫

35

为什么std::vector<string> vecCityNames;不好?

匈牙利表示法通常使用的问题是,如果分析表明应该将城市名称保留在中std::deque,则所有引用该类型对象的变量名称都将突然具有误导性的名称。

然后要重命名所有变量吗?您是否曾尝试在大型项目中做到这一点?在Murphy的帮助下(那里的人提供了非常多的帮助),某个地方的人肯定会使用诸如这样的变量deqCityNames,使您的更改破坏了构建,使您坐了数小时来摆弄代码,在过去的五年中,没有人敢于看因为害怕被有毒的野兽咬伤。

但是,据我所知,查尔斯·西蒙尼(Charles Simonyi)提出匈牙利语的方式是,该前缀表示变量的语义用法,而不是其句法类型。也就是说,无论采用哪种类型,城市名称列表的正确前缀都可能是listCityNames(或者lstCityNames,如果list对您来说不够神秘)。

但是我认为该前缀是多余的,因为复数(“名称”)已经表明它是一堆城市。底线:当您仔细选择标识符时,几乎不需要匈牙利符号。从长远来看,OTOH的常用用法实际上是在破坏代码。


6
@Coder:该类型在整个项目中都会使用,并且此类型的所有变量都将带有前缀。您将不必重命名一个全局变量,而是数百个局部变量。
2011年

7
您应该在Joel Spolsky的博客文章中添加一个链接,其中他解释了为什么使用变量类型来发出匈牙利语通知是对所有含义的误解。您的好,但有些人可能正在寻找更权威的东西,您可以用它来支持您的案子。joelonsoftware.com/articles/Wrong.html
Shane Wealti 2011年

2
@Coder:不幸的是,它typedef是一个被严重低估的工具
sbi 2011年

4
@Shane:我已经写下了自己对此事的看法。如果这与乔尔的观点相符,那对我很好,因为即使我不同意其中的一些观点,我也很重视他的观点。但是当我基于十多年来之不易的经验得出的结论时,我认为没有必要呼吁其他“当局”支持我的观点。很高兴您发布了该链接,但是,很高兴看到其他人的观点与之比较。
2011年

4
很久以前,我是这家商店的CVS负责人,一位顶级开发人员更改了姓名的首字母(例如做变性手术等,他和她的名字没有相同的缩写)。每当她触摸文件(或类似文件)时,她都会将他的所有姓名首字母都更改为新格式。我发现这非常烦人,因为我们会对历史特征进行各种各样的细微更改,而且很难弄清实际更改了什么以及为什么更改了。更改vecCityNamesdeqCityNames数百个文件,您将执行相同的操作。
David Thornley

15

无论出于何种原因,这里的现有答案似乎都围绕着匈牙利表示法的基本原理,而没有直接说明。在语言本身很难做到的情况下,匈牙利表示法可用于添加类型信息(从类型理论上来说)。碰巧的是,使用C ++或Java的类型系统通常并没有那么困难,以至于匈牙利符号(如通常所描述的)是完全多余的,这可能导致对此产生强烈反对-它增加了程序员的工作可以在我们所有的变量变量中保留这些注释,但是却几乎没有附加值(甚至可能会造成伤害,因为代码看起来更加混乱)。

另一方面,如果有人限制使用匈牙利符号来键入信息(同样,从理论上讲),则不是自然地被语言封装,那么它会非常有用。例如,C和C ++将数组引用作为指针类型传递,但是数组引用和指针具有针对它们执行的不同操作:可以在第一个元素之外对数组建立索引,而指针则不能。这是有用的信息,一旦将数组作为参数传递给函数,该信息就会丢失到类型系统中。因此,在我们的小组中,我们在C和C ++代码中采用了变量名注释,以区分指针变量实际上是指向单个元素的指针还是指向数组的指针。采用此约定在很大程度上减少了我们代码库中内存损坏问题的发生。


导致匈牙利人失败的原因是(WinAPI团队)滥用它来编码变量的语法类型,而不是其语义。(想想dw对比cb)。这并不是说原来的形式将是面向对象的语言少有所帮助:指数仍然是一个指数,即使储存在一个类类型,而不是内置的。
2011年

1
+1指出这里的真正论点是关于类型理论的。匈牙利表示法是一种用于使用附加信息来增强类型系统的技术,因此应与其他用于增强类型系统的技术(例如,模板,typedef等)进行比较和对比,而不是就其美学价值进行讨论(或缺乏)。
丹尼尔·普赖登2011年

1
问题特别是关于“ Systems Hungarian”(已声明类型的无意义重复),没有额外的语义信息。在某些情况下,可能会使用语义标记的原始“匈牙利符号”概念来提供超出语言语法允许范围的信息(在某些语言中,包括C,但不是C ++,您可以使用用户定义类型更可靠地完成此操作) ),但这不是问题所在。
Mike Seymour,

10

惹恼了一些人(不知道为什么)

之所以让我感到烦恼,是因为每个标识符的速度都有些慢,这减慢了我对代码的视觉扫描速度。如果您对q读iEnglish cText像这样,则可能是mAs。


9

仇恨这个词太强了,IMO。您可以根据需要编写代码。我只是不想在自己的代码中使用匈牙利表示法,并且给出选择后,我也不想在其他人的代码中阅读或使用它。

您问为什么有些人觉得匈牙利的符号很烦人。我不能为别人说话,但是惹恼我的原因是:

  1. 它很丑。匈牙利人使用完全合理的名称,并在代码前加上了前缀。将代码内部化之后,我相信这是完全合理的,但是对于未开始使用的人来说,就像是有人在我的源代码上释放了C ++名称错误。

  2. 这是多余的。变量的声明确定其类型;我觉得不需要在变量名中重复该信息。并非在每种语言中都是如此:例如,在Perl中,变量名之前的@$之类的信号基本上定义了变量的类型,因此您别无选择,只能使用它们。

  3. 它解决了我没有的问题。方法和函数的时间不要太长,以至于您不得不费劲地查找局部变量或参数的声明,并且它们不应该涉及太多的变量,以至于您难以跟踪什么是什么。在这方面,声明局部变量靠近使用它们的代码也有帮助。过去的C编译器要求在函数的开头声明所有局部变量,但是该限制早已被删除。

  4. 还不完整 匈牙利表示法是针对没有类型系统的语言(BCPL)发明的,后来在具有相当有限的本机类型的语言(C)中广泛使用。IMO,它不适用于具有大量类型系统的C ++或Java之类的语言。为什么我要使用前缀来表示本机类型的变量的类型,例如char [],而不是类的变量呢?或者,如果我开始发明vec类的前缀,那么最终我将得到一大堆与我的类层次结构平行的前缀层次。如果这对您有吸引力,那么欢迎您;欢迎您。只是想这让我头疼。

  5. 这是模棱两可的,至少据我了解。szFoo和之间有什么区别pszFoo?第一个是零终止字符串,第二个是指向零终止字符串的指针。但是据我所知,在C或C ++中,任何字符串变量实际上都是指针,所以它们相同还是不同?我应该使用哪个?实际答案确实无关紧要-关键是我无法使用本该用来帮助我避免此类问题的符号来识别答案。另一方面,变量的声明必须是明确的,因为它是编译器使用的。

这些就是让烦恼于匈牙利符号的事情。即使是一个团体,我也不认为他们完全解释了为什么匈牙利人被大量抛弃。这是大多数程序员不使用匈牙利语的三个最大原因:

  1. 没有令人信服的理由使用它。请参阅上面的项目3和4。如果匈牙利语比不使用匈牙利语提供了很大的优势,那么我可能会忍受烦恼,但是我看不到,而且其他大多数人也没有。也许关于匈牙利语的最好的事情是它是一种被广泛使用的约定,如果您坚持使用标准约定,则可以合理地期望其他具有类似技能的程序员能够理解该表示法。

  2. 非微软公司的影响力增加。可以公平地说,大多数采用匈牙利表示法的程序员都是这样做的,因为这是Microsoft编写代码的方式,并且通常更容易使用。像Google和Apple这样的公司现在的影响范围比过去大得多,并且比以往任何时候都更多的程序员采用了那些避开匈牙利语的公司和其他公司的风格。(公平地指出您仍然会看到一些残留,例如Google和Apple都经常使用'k'前缀作为常量名称。)

  3. 微软本身已经放弃了匈牙利语。如果检查其编码指南的Microsoft“ 常规命名约定”部分,则会发现它以粗体显示:不要使用匈牙利表示法。

因此,停止使用匈牙利表示法的一个有效原因是:

匈牙利符号的流行程度已降低到该公约不再有用的地步。如今,很少有程序员使用或什至不了解匈牙利语,因此,该约定在传达应有的信息方面效果不佳。如果您发现在自己的个人项目中编写代码的有用方法,那就没有必要停下来了。但是,如果您是在不使用匈牙利语的团队中编写代码的,那么它可能会成为您与团队其他成员之间的隔离墙,而不是成功的沟通策略。


szFoo和之间有什么区别pszFoo?” 一个是char*,另一个char**是我花了0.25秒的时间来分辨差异。尝试用Intellisense击败它。
编码器

2
@Coder pnFoo可能是int*,而不是int**,因此您必须知道,sz也意味着一个指针。我相信对于建立匈牙利前缀的有限类型来说,这不是什么大问题,但是在任何大型项目定义的类型中,成千上万的类型都是如此。我不了解Intellisense,但在过去25年中,IDE一直在稳步改进,我希望这种趋势会持续下去。
Caleb

8

到目前为止,我发现使用它具有以下好处:

  • 一致的变量命名

如果我用《辛普森一家》中的角色命名所有变量,那也是一致的,但这有好处吗?

  • 您无需搜索即可看到类型(智能在半数时间中已失效/已建立索引,因此这仍然是一个合理的原因)

基于一个特定工具的弱点,这是唯一有效的理由...

  • 语义仍然可以包含在名称的第二部分中

那不是好处。您只是声称没有(巨大的)负面影响。


6

当我将鼠标悬停在变量上时,IDE会告诉我变量的类型是什么。那么,为什么要麻烦复制这些信息呢?从根本上讲,Systems匈牙利表示法是对DRY的违反,它带有所有与之相关的陷阱。当在现代环境中轻松获得这些信息时,就没有理由为此付出代价。

一致性本身并不是一个优势。不使用类型命名它们也是一致的。如果名称中只有某些变量的类型,则只会出现不一致的情况。将语义打包到第二部分中只是“嗯,还不错。”,其他所有人都可以使用名来表示语义。您没有列出任何真正的优势。


4
“当我将鼠标悬停在变量上时,IDE会告诉我变量的类型是什么。”,在问候世界中,是的。在较大的项目中,我发现此功能极其不可靠/缓慢。ctrl + space,ctrl + space,ctrl + space,ctrl + space,ctrl + space,no go ...
Coder

3
获取一个新的IDE。或SSD,行之有效。或者只包含较少不必要的标头。
DeadMG

1
即使IDE在显示变量类型时速度太慢,或者根本无法做到这一点,方法/函数也应保持简短,这样变量的声明就永远不会离它的使用很远。
凯文·潘科

6

传统形式的匈牙利符号的另一点是,它们通常是前缀。恕我直言,这里有两个问题:

1)人类读者通常会首先喜欢最重要的信息,在大多数形式的匈牙利语中,可以说编码的信息的重要性不如名称本身。

2)前缀影响词法排序,因此,例如,如果您要使用前缀来表示接口或类,并且您的IDE提供了这些的排序列表,则相关的类/接口将在此列表中分开。


2

显然,这取决于意见,因此在这里很难处理事实。就个人而言,我觉得该参数匈牙利命名法运行在强类型,面向对象的语言有点薄。以我的经验,OO应用程序倾向于通过保持类的连贯性和简洁性来处理复杂性,关于功能也可以这样说。这意味着在所有其他条件相同的情况下,您最终得到:

  • 更多类别/类型
  • 较短的方法

现在,如果要使用匈牙利表示法,则必须决定是全面使用它,还是仅将其用于某些特权类型和类(例如核心库类)。后者对我而言毫无意义,而前者导致了PéterTörök所指的“试图找到千种不同缩写的迷宫”。这意味着在维护缩写列表时会产生很大的开销,并且通常“一致变量命名”已不再可用。

关于较短方法的第二点意味着,在大多数情况下,您将不必通过数百行代码来检查变量的类型。稍微更仔细地命名变量将消除您的其他一些问题-例如cityNamevs. just city。我希望这cityName不是一个浮动:)

关于它为什么使人烦恼-再次,这很可能归因于它是否习惯了。但是作为一个不习惯它的人,我可以告诉您,匈牙利符号的使用打乱了我的眼睛,使代码难以快速阅读。总而言之,我并不是说它没有优点(尽管我没有在重构方面讨论过它的某些缺点),我说的是,对于强类型的OO语言,这样做是不值得的。


1

我在C ++的上下文中并不知道,但是在Java / C#领域中,我更喜欢使用有意义的名称来传达域语言或上下文,而不是告诉我它strFirstName是字符串。很明显,这是一个字符串,或者需要重构名称以传达更好的意图。如果您需要一个前缀来知道您正在使用的类型,那么我会认为您的命名不一致,描述性不够或完全错误。在现代语言中,我总是更喜欢名称较长的名称,而不要使名称含糊不清或模棱两可。

我唯一使用匈牙利语的时候是用于ASP.NET控件,而且更重要的是IA)不必键入很长的内容,例如CustomerFirstNameTextBoxvs txtCustomerFirstName和B),因此Intellisense可以对所有控件类型进行排序。即使这样做,我仍然感到“肮脏”,但我还没有找到更好的方法。


0

嗯-实际上,这完全取决于个人喜好,无论人们如何努力使自己的选择合理化。我个人遵循“何时在罗马……”规则,并在经常调用Windows API的代码中使用匈牙利语。对于独立于平台的代码,我倾向于遵循C ++标准库样式。


0

答案就在于这个问题:请告诉我如何命名以下变量:

char * nullTerminatedString;
wchar * nullTerminatedWideString;
字符串stlString;
wstring stlWideString;
CString mfcString;
BSTR comString;
_bstr_t atlString;

在这些常量字符串中,添加指向这些常量的指针和指向这些常量的指针。


3
szFoowczFoostrFoo(w)strFoostrFoobstrFoobstrFoo
编码器

0

我非常不喜欢您描述的匈牙利符号形式。原因?90%的时间没有用。

例如,我不得不忍受的一个遗留项目中的一些(相当于C ++。实际上是用Delphi编写的)代码:

pRecords[0]->FooMember=10;

... pRecord是一个变量,其类型为TRecordList。 TRecordList *pRecords[10];

这是一个由名为FooMember的对象组成的类,该对象指向fFooMember ...或mFooMember,具体取决于它是“字段”还是“成员”(提示:它们是同一件事)

问题?fFooMember可能类似于FooMember_,因为我们将始终通过FooMember公共属性对其进行访问。pRecords?很明显,这是您在各处取消引用的事实的指针。TRecordList?什么时候可以混淆类型名称和该类型的对象?编译器会大吼大叫,类型几乎不在对象使用的地方使用(静态属性/方法除外)

现在,有一个地方我确实使用匈牙利符号。这是在处理许多与其他UI变量或常规变量同名的UI变量时。

例如,如果我上面有您名字的表格。

我有一个名为FirstNameForm的类。其中的lblFirstName和txtFirstName分别用于标签和文本框。还有一个公共的FirstName属性,用于获取和设置文本框中的名称。

这也可以通过使用FirstNameLabel和FirstNameTextBox解决,但我发现键入它的时间太长了。特别是像GenderDropDownList之类的东西。

因此,基本上,匈牙利符号充其量是在系统层次上令人讨厌,最坏的情况是有害的(因为其他答案都涉及重构和一致性问题)。

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.