It appears that some people interpreted the title of one of my rants from many months ago, "Cleaner, more elegant, and wrong", to be a reference to exceptions in general. (See bibliography reference [35]; observe that the citer even changed the title of my article for me!)

The title of the article was a reference to a specific code snippet that I copied from a book, where the book's author claimed that the code he presented was "cleaner and more elegant". I was pointing out that the code fragment was not only cleaner and more elegant, it was also wrong.

You can write correct exception-based programming.

Mind you, it's hard.

On the other hand, just because something is hard doesn't mean that it shouldn't be done.

Here's a breakdown:

Really easy Hard Really hard
Writing bad error-code-based code
Writing bad exception-based code
Writing good error-code-based code Writing good exception-based code

It's easy to write bad code, regardless of the error model.

It's hard to write good error-code-based code since you have to check every error code and think about what you should do when an error occurs.

It's really hard to write good exception-based code since you have to check every single line of code (indeed, every sub-expression) and think about what exceptions it might raise and how your code will react to it. (In C++ it's not quite so bad because C++ exceptions are raised only at specific points during execution. In C#, exceptions can be raised at any time.)

But that's okay. Like I said, just because something is hard doesn't mean it shouldn't be done. It's hard to write a device driver, but people do it, and that's a good thing.

But here's another table:

Really easy Hard Really hard
Recognizing that error-code-based code is badly-written
Recognizing the difference between bad error-code-based code and not-bad error-code-based code.
Recognizing that error-code-base code is not badly-written
Recognizing that exception-based code is badly-written
Recognizing that exception-based code is not badly-written
Recognizing the difference between bad exception-based code and not-bad exception-based code

Here's some imaginary error-code-based code. See if you can classify it as "bad" or "not-bad":

BOOL ComputeChecksum(LPCTSTR pszFile, DWORD* pdwResult)
{
HANDLE h = CreateFile(pszFile, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE hfm = CreateFileMapping(h, NULL, PAGE_READ, 0, 0, NULL);
void *pv = MapViewOfFile(hfm, FILE_MAP_READ, 0, 0, 0);
DWORD dwHeaderSum;
CheckSumMappedFile(pvBase, GetFileSize(h, NULL),
&dwHeaderSum, pdwResult);
UnmapViewOfFile(pv);
CloseHandle(hfm);
CloseHandle(h);
return TRUE;
}

This code is obviously bad. No error codes are checked. This is the sort of code you might write when in a hurry, meaning to come back to and improve later. And it's easy to spot that this code needs to be improved big time before it's ready for prime time.

Here's another version:

BOOL ComputeChecksum(LPCTSTR pszFile, DWORD* pdwResult)
{
BOOL fRc = FALSE;
HANDLE h = CreateFile(pszFile, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (h != INVALID_HANDLE_VALUE) {
HANDLE hfm = CreateFileMapping(h, NULL, PAGE_READ, 0, 0, NULL);
if (hfm) {
void *pv = MapViewOfFile(hfm, FILE_MAP_READ, 0, 0, 0);
if (pv) {
DWORD dwHeaderSum;
if (CheckSumMappedFile(pvBase, GetFileSize(h, NULL),
&dwHeaderSum, pdwResult)) {
fRc = TRUE;
}
UnmapViewOfFile(pv);
}
CloseHandle(hfm);
}
CloseHandle(h);
}
return fRc;
}

This code is still wrong, but it clearly looks like it's trying to be right. It is what I call "not-bad".

Now here's some exception-based code you might write in a hurry:

NotifyIcon CreateNotifyIcon()
{
NotifyIcon icon = new NotifyIcon();
icon.Text = "Blah blah blah";
icon.Visible = true;
icon.Icon = new Icon(GetType(), "cool.ico");
return icon;
}

(This is actual code from a real program in an article about taskbar notification icons, with minor changes in a futile attempt to disguise the source.)

Here's what it might look like after you fix it to be correct in the face of exceptions:

NotifyIcon CreateNotifyIcon()
{
NotifyIcon icon = new NotifyIcon();
icon.Text = "Blah blah blah";
icon.Icon = new Icon(GetType(), "cool.ico");
icon.Visible = true;
return icon;
}

Subtle, isn't it.

It's easy to spot the difference between bad error-code-based code and not-bad error-code-based code: The not-bad error-code-based code checks error codes. The bad error-code-based code never does. Admittedly, it's hard to tell whether the errors were handled correctly, but at least you can tell the difference between bad code and code that isn't bad. (It might not be good, but at least it isn't bad.)

On the other hand, it is extraordinarily difficult to see the difference between bad exception-based code and not-bad exception-based code.

Consequently, when I write code that is exception-based, I do not have the luxury of writing bad code first and then making it not-bad later. If I did that, I wouldn't be able to find the bad code again, since it looks almost identical to not-bad code.

My point isn't that exceptions are bad. My point is that exceptions are too hard and I'm not smart enough to handle them. (And neither, it seems, are book authors, even when they are trying to teach you how to program with exceptions!)

(Yes, there are programming models like RAII and transactions, but rarely do you see sample code that uses either.)

Cleaner, more elegant, and harder to recognize (msdn blog)的更多相关文章

  1. Cleaner, more elegant, and harder to recognize(翻译)

    Cleaner, more elegant, and harder to recognize 更整洁,更优雅,但更难识别 看来,有些人把我几个月前一篇文章的标题"Cleaner,more e ...

  2. Cleaner, more elegant, and wrong(msdn blog)

    Cleaner, more elegant, and wrong Just because you can't see the error path doesn't mean it doesn't e ...

  3. Cleaner, more elegant, and wrong(翻译)

    Cleaner,more elegant,and wrong 整洁,更优雅,但是错的 并不是因为你看不到错误的产生路径就意味着它不存在. 下面是C#编程书中的一个片段,摘自关于异常处理的章节. try ...

  4. Go 开发关键技术指南 | 敢问路在何方?(内含超全知识大图)

    作者 | 杨成立(忘篱) 阿里巴巴高级技术专家 Go 开发关键技术指南文章目录: 为什么你要选择 Go? Go 面向失败编程 带着服务器编程金刚经走进 2020 年 敢问路在何方? Go 开发指南大图 ...

  5. Go 开发关键技术指南 | Go 面向失败编程 (内含超全知识大图)

    作者 | 杨成立(忘篱) 阿里巴巴高级技术专家 关注"阿里巴巴云原生"公众号,回复 Go 即可查看清晰知识大图! 导读:从问题本身出发,不局限于 Go 语言,探讨服务器中常常遇到的 ...

  6. diff/merge configuration in Team Foundation - common Command and Argument values - MSDN Blogs

    One of the extensibility points we have in Team Foundation V1 is that you can configure any other di ...

  7. C# Development 13 Things Every C# Developer Should Know

    https://dzone.com/refcardz/csharp C#Development 13 Things Every C# Developer Should Know Written by ...

  8. EF 5 最佳实践白皮书

    Performance Considerations for Entity Framework 5 By David Obando, Eric Dettinger and others Publish ...

  9. Build Instructions (Windows) – The Chromium Projects

    转自:http://121.199.54.6/wordpress/?p=1156 原始地址:http://www.chromium.org/developers/how-tos/build-instr ...

随机推荐

  1. Java第三季

    1.异常简介: (1) Java中的所有不正常类都继承于Throwable类.Throwable主要包括两个大类,一个是Error类,另一个是 Exception类: (2)其中Error类中包括虚拟 ...

  2. Servlet&JSP-HTTP服务器响应信息

    完整代码请参考:https://github.com/devway9/java-exercise/tree/master/servlet-jsp 目录 1 HTTP响应的格式 2 如何设置状态代码 3 ...

  3. js实现关键词高亮显示 正则匹配

    html 和ajax 部分就不写了,只需将需要匹配的文字传进去就可以了 比如匹配后台传回的字符串data.content中的关键词:直接调用: data.content = highLightKeyw ...

  4. RGBA 和 opacity的区别

    两者都可以设置透明度 区别 RGBA 只影响当前元素 opacity 后代会继承该css 值,暂时还没有办法清除该css 在线演示

  5. 51Nod 1084 矩阵取数问题 V2 双线程DP 滚动数组优化

    基准时间限制:2 秒 空间限制:131072 KB  一个M*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励,先从左上走到右下,再从右下走到左上.第1遍时只能向下和向右走,第2遍时只能向 ...

  6. 前端测试框架Jest系列教程 -- Mock Functions

    写在前面: 在写单元测试的时候有一个最重要的步骤就是Mock,我们通常会根据接口来Mock接口的实现,比如你要测试某个class中的某个方法,而这个方法又依赖了外部的一些接口的实现,从单元测试的角度来 ...

  7. 一键架设FastDFS分布式文件系统脚本,基于Centos6

    一.使用背景 业务驱动技术需要,原来使用 FTP和 Tomcat upload目录的缺陷日渐严重,受限于业务不断扩大,想使用自动化构建,自动化部署,Zookeeper中心化,分布式RPC DUBBO等 ...

  8. Java web轻量级开发面试教程的前言

    本文来是从 java web轻量级开发面试教程从摘录的. 为什么要从诸多的Java书籍里选择这本?为什么在当前网络信息量如此大的情况下还要买这本书,而不是自己通过查阅网络资料学习?我已经会开发Java ...

  9. 自学Zabbix3.8-可视化Visualisation

    随着大量数据流入Zabbix,如果用户能够查看正在发生的事情,而不仅仅是数字,那么对于用户来说,这就变得容易得多了.这就是图的所在. 图允许快速地掌握数据流,关联问题,发现什么时候开始,或者做什么事情 ...

  10. mango(mango ORM框架介绍)

    官网地址:http://www.jfaster.org/ mango的中文名是"芒果",它是一个极速分布式ORM框架.目前已有十多个大型线上项目在使用mango,在某一支付系统中, ...