Cleaner, more elegant, and harder to recognize (msdn blog)
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 | ||||||
---|---|---|---|---|---|---|---|---|
|
|
|
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)的更多相关文章
- Cleaner, more elegant, and harder to recognize(翻译)
Cleaner, more elegant, and harder to recognize 更整洁,更优雅,但更难识别 看来,有些人把我几个月前一篇文章的标题"Cleaner,more e ...
- 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 ...
- Cleaner, more elegant, and wrong(翻译)
Cleaner,more elegant,and wrong 整洁,更优雅,但是错的 并不是因为你看不到错误的产生路径就意味着它不存在. 下面是C#编程书中的一个片段,摘自关于异常处理的章节. try ...
- Go 开发关键技术指南 | 敢问路在何方?(内含超全知识大图)
作者 | 杨成立(忘篱) 阿里巴巴高级技术专家 Go 开发关键技术指南文章目录: 为什么你要选择 Go? Go 面向失败编程 带着服务器编程金刚经走进 2020 年 敢问路在何方? Go 开发指南大图 ...
- Go 开发关键技术指南 | Go 面向失败编程 (内含超全知识大图)
作者 | 杨成立(忘篱) 阿里巴巴高级技术专家 关注"阿里巴巴云原生"公众号,回复 Go 即可查看清晰知识大图! 导读:从问题本身出发,不局限于 Go 语言,探讨服务器中常常遇到的 ...
- 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 ...
- 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 ...
- EF 5 最佳实践白皮书
Performance Considerations for Entity Framework 5 By David Obando, Eric Dettinger and others Publish ...
- Build Instructions (Windows) – The Chromium Projects
转自:http://121.199.54.6/wordpress/?p=1156 原始地址:http://www.chromium.org/developers/how-tos/build-instr ...
随机推荐
- 重要:关于PPT转图片需要注意的问题
关于PPT转图片的问题需要注意的问题 我们有一个项目做过直接上传ppt的功能,但是网页不可能显示ppt,所以只能把ppt转成pdf或者图片来显示,我们的做法是转成了图片,然后使用swiper做成类 ...
- Linux EXT 文件系统 详解
上几章我们讲到了Linux启动的一些问题,接下来我们来看一下硬盘分割和EXT格式文件系统的问题.前面提到了分区表的问题,分区表位于MBR, 占用64个字节.所谓的硬盘分区也就是对硬盘进行规划,填写分区 ...
- apache通过AD验证
## apache通过AD验证 #yum install httpd mod_authz_ldap#安装apahce的ldap模块yum install mod_authz_ldap -y #配置ap ...
- Python中的选择排序
选择排序 选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理如下.首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大 ...
- “核弹级”Android漏洞Janus,黑客可以任意篡改App
美国时间12月9日,Google披露了一个名为"Janus"安卓漏洞.该漏洞可以让攻击者绕过安卓签名机制,从而让攻击者对App进行篡改,安卓5.0到8.0等个版本系统均受影响. 顶 ...
- Linux下如何彻底删除MySQL
1.查找以前是否装有mysql 命令:rpm -qa|grep -i mysql可以看到如下图的所示: 说明之前安装了:MySQL-client-5.5.25a-1.rhel5MySQL-server ...
- 深入理解php内核 编写扩展_III- 资源
原文:http://devzone.zend.com/article/1024-Extension-Writing-Part-III-Resources 编写扩展_III- 资源 介绍 资源 初始化资 ...
- oracle中 merge into 的用法
很多时候我们需要通过筛选条件同时对表进行 更新,插入,删除 等操作.这样如果我们单一的去操作表会显得很麻烦,下面会说到这个merge into 的用法会极大的优化我们操作表的时间和代码量. 举例,先 ...
- dubbo源码—SPI
Java中的SPI SPI,Service Provider Interface,java中提供的一种使程序可扩展的方式,系统定义好接口规范,供其他服务提供方实现,服务提供方将自己jar包META-I ...
- BigInteger详解
在Java中有两个类BigInteger和BigDecimal分别表示大整数类和大浮点数类,理论上能够表示无线大的数,只要计算机内存足够大. 这两个类都在 java.math.* 包中,因此每次必须在 ...