系列列表:

【翻译】对话:究竟谁才是可移植的程序员?

【翻译】对话:接触指针

【翻译】对话:换个名字

“嗨,小鬼。”Jeannine走过来坐在我对面,我现在很邋遢。“听说消息了吗?”

我扫了一眼时间确认一下,我并不打算再跟她聊半个小时以上。“嗨,二等公民。不,还不是。无论如何,他们仍在值班。你今天这么早就不值班了?”

“Brzenkowski睡不着,所以他跟我换班了。我欠了他一次。”

“他真体贴,”我又吃了一口午餐同意道,“我真的很喜欢他,他经常加班,而且并不会影响到其他人,他知道如何融入到这个环境中来。但愿我们在下个月的行星登陆(planetfall)以后还能与他一起工作。任何人都该如此专业。”

“大多数人都是的,”Jeannine笑了。“你自己也不赖阿。”

“实际上,”我咯咯笑了笑,“你让我想起了bob。你知道,我以前跟你提过他,他是我第一次工作遇到的另一个怪人。哥们,有时他做起事情来能让你把肺气炸。因此如果有人默不作声的工作,我们都叫他‘胡扯Bob’”

我继续讲述我的故事…


一个声音在我耳边响起:“嘿,新来的,你破坏了结构。”

我暗暗叹了口气,然后闭上了我的眼睛。我做这份工作已经快2个月了,我早就开始讨厌Guru叫我‘我的学徒’,但也不及这个没用的程序员Bob这样叫我-尤其是“新来的”。我数到10,然后直直的回答:“Bob,你在说什么?”

“你的新代码check in了,”Bob温和地回复,吸了口他的拿铁咖啡(latté)。“我的编译器不能通过。它在抱怨一个迭代器已经定义过了。你破坏了结构,朋友。在头儿发现之前赶紧改掉把。”我缩了一下,我还不熟练,我知道破坏结构是很糟糕的事情。我甚至可以想象到Guru知道后的反应:记住,我的小学徒,团队合作的第二条戒律就是绝对不要破坏结构。

“好吧,”我又叹了口气,这次乖了。“你在说代码的哪个部分?”

Bob弯下身,打了几个键,弄出了下面的函数:

//OBJMAP是一种标准容器的typedef
void f(OBJMAP &theMap)
{
 for(OBJMAP::iterator iter = theMap.begin();
     iter != theMap.end();
     ++iter)
 {
 //do something
 }
 //other code in here
 for(OBJMAP::iterator iter = theMap.begin();
     iter != theMap.end();
     ++iter)
 {
 //do something else
 }
}

“这里有错误吗?”我问道。“我在Stroustrup里把它check out了,迭代器应该在每一个循环结束时超出了范围。”

“是啊,是要这样的,但我的编译器不支持。”Bob回答说,剔着自己的牙齿。“它抱怨说iter已经定义了。很容易的更改吧,仅仅只是去掉iter的第二次定义。实际上,当我check in 它的时候,那就是我的代码起始如何读进去的。然后你的代码运行的时候破坏了结构。”

我终于明白了。由于我仍在在试用期,我不得不表现得很谦逊。“Bob,”我心有成竹,“这是必须在我们面对的所有平台上面编译的。我把第二个定义放上是因为我的编译器抱怨第二个迭代器没有定义,根据Stroustrup,他应该能工作。”

Bob似乎有些不耐烦。“我不在乎你的新编译器。我用我的很多年了,它从没有让我失望过。你的代码不能工作。”

“Bob,代码是正确的。在我这里编译没问题。”

“你的是个烂编译器。不是我的错,我在做我的工作,我不在乎别的编译器。”Bob又耸了耸肩,为自己辩护道。

一个响亮的声音在我们身后响起:“我感觉你有些害怕阿。”

我吓了一跳;Bob也好不到哪里,拿铁咖啡还在乱晃。Guru无声的在我们身后定住,手里还是拿着一本厚厚的书。

Guru慢慢的摇了摇头,皱了皱眉毛。“害怕导致愤怒。”她继续说道。

“哼,住口。我不担心别的编译器!”Bob激动的说,吸着溅落在他手上的奶咖啡。“我一点也不在乎它们。”

“愤怒导致仇恨。仇恨…导致苦难。”

“我是在受苦,没错,”我大气不敢喘,小声地嘀咕了声。“我只是想写出可移植的代码。-好吧,Bob,”我认输了,渴望摆脱掉他,“我会改掉它让它好好工作的,好吗?”

“就像我说的,新来的,去掉第二个声明就可以了。”他又看了看我,然后转过身走了。

Wendy靠着下一个隔间,看着他走了。“那么这次Bahb又在抱怨什么呢?”她问我。然后Guru靠近站了站,合上了她那本厚书,我给Wendy看了那段代码,解释了一下Bob要做的。“真是典型,”Wendy有点生气,“在实现一个可移植的方案和依赖于他的编译器的方案之间选择的话,他会毫不犹豫选择后者。就像你说的,他的代码不具有可移植性。你知道,这样的话,你就真的不需要在每个循环声明一个新的迭代器。只在第一个循环之前声明它们一次,它们就可以在两种编译器下都良好工作。”她快速改变了一下那段代码:

// OBJMAP is a typedef for a standard container
void f(OBJMAP &theMap)
{
    OBJMAP::iterator iter;
    for( iter = theMap.begin();
         iter != theMap.end();
         ++iter ) {
        // do something
    }
    // other code in here
    for( iter = theMap.begin();
         iter != theMap.end();
         ++iter ) {
    // do something else
    }
}

Guru检查了一下自己的书写,扫了一眼这个方案。“非常聪明,孩子。”Wendy轻挑眉梢:她常常这样。“而且如你所说,这不是惟一的方案。另一个优雅的可能是干脆避免迭代器的声明,也许提高了可读性,通过在可能的地方使用for_each和模板表达式。我的学徒。”Guru继续对我说,“但是了解,理解和遵守神圣标准是很重要的,了解你的工具甚至那些不正常的也很重要。Bob在使用的那个编译器不服从for初始化变量的范围。他不在乎可移植的代码,只在乎自己的编译器。”

“嗯…”我说,摸了摸自己的下巴。“写可移植的代码比我想的要困难,所以,在我们可以利用我原先的代码前,不得不等着Bob的编译器出新的版本了。”

Guru注视着自己前方好一会。“我不是先知,我看不到未来。虽然如此,我还是能看到:可移植的发布绝对不会消失。编译器不都是遵守标准的-只是在级别上保持一致罢了。一些开发商甚至已经在他们的编译器里摒弃了过时的行为,而并不是一味迎合旧代码。

“而且,一些编译器会产生出新的特性来扩展标准。有一些是很好的,还有一些会使语言趋于陈腐,没有弹性,最终会亡于停步不前。只适应一个平台的程序可能从新特性中获益。在可移植代码中使用那些非标准的特性有时是灾难性的-有些见习生,比如你,可能不注意他们的不可移植性而滥用它们。不要只钟爱于某一个编译器而害怕其他的。害怕就要导致不能移植。”

她停了一下,然后转身走了。随着她的离开,她绵绵的声线飘入我们的耳朵,“但愿我能记起那位圣人的名字,他曾经说过,‘理论和实践的区别总是在实践中更明显…’”


“Bob并不是一个融入大局的家伙,”我总结道。

“在Ganymede号上没有人是这样的,”Jeannine也同意。“这并不是一个可以原谅的地方。嘿,你得走了。Anderson在等你。”

我看了看时间站了起来。“职责呼叫。在第三次调查后你和Laura在做什么?”我问,因为我发现了那儿,当然,还有比谈论Bob更舒适的事情,比如Guru…