Prev: Deriving from a class derived from a CDialog
Next: How to show underlined menu shortcut letters by default for a contextmenu ?
From: Goran on 24 Jun 2010 04:06 On Jun 23, 5:39 pm, Hector Santos <sant9...(a)nospam.gmail.com> wrote: > public bool SearchForums(string sPattern) > { > try > { > > Regex rgx = new Regex(sPattern, RegexOptions.IgnoreCase); > foreach (var forum in ForumsList) > { > MatchCollection matches = rgx.Matches(forum.Description); > if (matches.Count > 0) > { > /// got something > } > } > return true; > } > catch (Exception ex) > { > MessageBox.Show("Regular Expression Error: " + ex.Message); > } > return false > > } (Please don't think I am picking on you, it's just that this snippet really makes my hear stand up on my back) That's a horrible way to handle exceptions. First off, you can't catch an Exception and say ""Regular Expression Error: ". That's simply false. If nothing else, you could be out of memory. On a more general note, in many-a-situation, you simply have no idea what exactly went wrong, and going specific is an error. I think I know why you did this, too: it's because people who struggle with exceptions are in over-reaching fear of losing error context, error context being e.g.: OK, I have this regexException, but once caught, question is, where exactly did it happen and for what reason (e.g. what inputs or program state etc). That loss of context is luckily easily solved in rich execution environments à la .NET: inner exceptions. So in your case, __if__ you think that you need more context, you would do an equivalent of: class MoreSpecificException { MoreSpecificException(params, Exception inner) {...} } ResultType f(params) { try { workworkwork; return someresult; } catch(RegexException e) { throw new MoreSpecificException(additional "context" info, e); } } (But, as I said to RB, you are, just like him, not allowed to write a try/catch ;-). When you think you need one, stop and think; question to ask is "where is this caught if I do nothing?"). Second, this function presumes that there's a good context to go on the screen with error message. That's a BIG presumption. E.g. what if this is not called from the main thread? What if I want to call it elsewhere (re-usability is low). And third, that function STILL can exit with an exception. E.g. OOM, or other resource shortage happened in your catch. So you potentially lie to your caller. All in all, that's a really poor way to write code with exceptions. In fact, in exception-enabled environments, attempts to write error- return code (you did that there) are often horribly misguided. Please, for the love of God, don't do this. One can kinda-sorta escape in MFC, but IMNSHO even there it's a bad idea. Goran.
From: Hector Santos on 24 Jun 2010 07:18 Goran, it was more of a tag, i.e. for tracing, something I do a lot when I am adding something I consider "abnormal" to immediately know where and what in the high possible levels of exceptions traps. I think I wrote that here when posting the highly truncated function, but the actual tag I have is: MessageBox.Show("SEARCH EXCEPTION: "+ex.Message); and again, that is a "tag" more than anything else. The actual function is 5-6 times larger. I see our points, but I won't agree it is "horrible." But again, you proved my point. Until you are completely aware of all the possible specific exceptions traps for a class, a documentation and learning issue, the "catch all" is going to be common place. For me, productivity wise, I am going wrap a catch all with a "tag" as the fastest way to get going as I always done for any language. Then the exercise of fine tuning it begins, possibly cleaning it up, adding the specifics as you laid out. Maybe Intellisense should have a macro for extracting from a selected class and wrapping try block adding all the possible specific exception catch blocks. Maybe its already there, I haven't checked. -- HLS Goran wrote: > On Jun 23, 5:39 pm, Hector Santos <sant9...(a)nospam.gmail.com> wrote: >> public bool SearchForums(string sPattern) >> { >> try >> { >> >> Regex rgx = new Regex(sPattern, RegexOptions.IgnoreCase); >> foreach (var forum in ForumsList) >> { >> MatchCollection matches = rgx.Matches(forum.Description); >> if (matches.Count > 0) >> { >> /// got something >> } >> } >> return true; >> } >> catch (Exception ex) >> { >> MessageBox.Show("Regular Expression Error: " + ex.Message); >> } >> return false >> >> } > > (Please don't think I am picking on you, it's just that this snippet > really makes my hear stand up on my back) > > That's a horrible way to handle exceptions. > > First off, you can't catch an Exception and say ""Regular Expression > Error: ". That's simply false. If nothing else, you could be out of > memory. On a more general note, in many-a-situation, you simply have > no idea what exactly went wrong, and going specific is an error. > > I think I know why you did this, too: it's because people who struggle > with exceptions are in over-reaching fear of losing error context, > error context being e.g.: OK, I have this regexException, but once > caught, question is, where exactly did it happen and for what reason > (e.g. what inputs or program state etc). That loss of context is > luckily easily solved in rich execution environments � la .NET: inner > exceptions. So in your case, __if__ you think that you need more > context, you would do an equivalent of: > > class MoreSpecificException > { MoreSpecificException(params, Exception inner) {...} } > ResultType f(params) > { > try > { > workworkwork; > return someresult; > } > catch(RegexException e) > { > throw new MoreSpecificException(additional "context" info, e); > } > } > > (But, as I said to RB, you are, just like him, not allowed to write a > try/catch ;-). When you think you need one, stop and think; question > to ask is "where is this caught if I do nothing?"). > > Second, this function presumes that there's a good context to go on > the screen with error message. That's a BIG presumption. E.g. what if > this is not called from the main thread? What if I want to call it > elsewhere (re-usability is low). > > And third, that function STILL can exit with an exception. E.g. OOM, > or other resource shortage happened in your catch. So you potentially > lie to your caller. > > All in all, that's a really poor way to write code with exceptions. In > fact, in exception-enabled environments, attempts to write error- > return code (you did that there) are often horribly misguided. Please, > for the love of God, don't do this. One can kinda-sorta escape in MFC, > but IMNSHO even there it's a bad idea. > > Goran.
From: Hector Santos on 24 Jun 2010 07:58 As an engineer, I look at all things the same way, i.e, the same issues, the same error points, the same I/O behavior. That is regardless of the language or framework because at the end of the day, we are all faced with the same issues - and it should be. On any given day, I have to work in about 4-6 or more languages and environments, today, its C, C++, Java, Javascript, VB, PHP, WCBASIC (our own), DELPHI Pascal, and now more of .NET, VB.NET, C#.NET and my dabbling in C++.NET and I probably missed a few, oh yeah, if we want to call it "languages", SQL, XML, HTML, ASP, WSP (Our own ASP), now I'm looking at LINQ and learning (actually restarting in earnest) writing many sub-classes and interfaces that we will need, all these need different levels of thinking. It can hurt the brain, but I manage it. I am a speed demon so I look for the fastest way to get going - fine tuning is an after thought. I think I am pretty good at getting it right the first time by this point, but I am also fully aware when somethings needs more intention and make a note of it mentally or inline comments. As it often the case, the devils are in the details, as such, 99% of the time, my comments here and even in most areas are more generalizations. Yet, I am fully aware that can be easy pickings for some that don't, won't or can't see the points. So I should be careful of that. That said, I don't think it is irrational at this day of age of having a knowledge base of the most possible errors seen and a common set of errors for a given sub-set or category of functions. Maybe that is part of being an Software Engineering expert - which is not necessarily programming - but interfacing systems and sub-systems. Case in point, I/O, there is a pretty well define set of highly probably errors and then ones that are common to general I/O. For fopen, for example, some people will view not found bad input (bad path) locked error sharing error are natural errors with a high expectation, with a certain level of natural recovery, while others are global and not highly recovery: out of memory out of disk space hard drive problem Again, don't focus on the attempts for details mentioned, but the generalization I am making. As I mentioned early, I still think exceptions are a crutch, but environments like .NET need them because of the high complexity mostly and also for the way methods are written as procedures, not as functions. Given a choice, some developers are are familar with both, will choose. Other, newer generation developers will most likely see it one way - traps. But if even the option, maybe they (or some) will using a boolean approach. There is no cut and dry answer - thats for sure. :) -- Goran wrote: > On Jun 23, 9:58 pm, Hector Santos <sant9...(a)nospam.gmail.com> wrote: >> That is why I say the real issue is the lack of documentation or the >> "hidden" knowledge that are wrapped into classes. >> >> When you use fopen(), you know what the possible errors are, basically >> >> invalid file path, error 2 >> not found, for a already exist mode, error 3 >> read/write sharing issue, error 5 or 32 >> >> but regardless of the error code, the #1 idea is that the FILE * >> stream variable is NULL. >> >> Some of the things I am coming across with .NET is that some old >> traditional and SOLID concept no longer apply. > > I disagree very much with this observation. The thing is, even fopen > has more failure modes than that (and they are probably OS-specific, > too). And fopen is a mighty simple, very low-level operation. > > On "big" frameworks like .NET, one function hides much much more > functionality, and consequently, much more failure modes. So without > exceptions, you can either simplify failure info going out of the > function to stay in a "manageable" situation (effectively, lie), > either make it effectively unmanageable by specifying all failure > modes. > > Here, case in point is a random Win32 API: it's BOOL fn(params), and > doc says: in case of failure, call GetLastError for more info. Seldom > it is defined what GetLastError might return. Why is that? Simply > because documenting all possible failure modes is mighty irrational. > > Goran. -- HLS
From: Goran on 24 Jun 2010 08:02 On Jun 24, 1:18 pm, Hector Santos <sant9...(a)nospam.gmail.com> wrote: > But again, you proved my point. Until you are completely aware of all > the possible specific exceptions traps for a class, a documentation > and learning issue, the "catch all" is going to be common place. Hey, I am trying to grind a different axe here! I am trying to say this: exceptions or error-return, it's both unrealistic and needles to be aware of / handle all possible exceptions / failure modes at any given place. It's easy to see why it's unrealistic: consider your own function somewhere in the call stack. Say that it can call X "base"/"system" functions, each having a small number of Y failure modes, some of them overlapping, for a total of e.g. X*Y*0.75 failure modes. Say that function is in usual win32/ CRT form of "BOOL result + GetLastError" How do you work with that? if (!myfunc(params)) switch (GetLastError()) { bloody hell, it's ful of cases! } ? Of course not. For the most part, you just do if (!myfunc(params)) return false; (or equivalent thereof) Typical error-return code looks like the above. IOW, for the most part (like, 90% of cases), it does not try to "handle" any failure modes at the place of the call. Well... (drum roll...) exceptions give you that behavior automatically (and number of failure modes does not change due to them; in that respect, there's no difference). But you seem to want to catch all these exceptions. Now I clearly have to ask: why? Just do "return false"! (That is, in case of exceptions, do nothing). That is the error of your ways WRT exceptions. No, seriously! > Maybe Intellisense should have a macro for extracting from a selected > class and wrapping try block adding all the possible specific > exception catch blocks. Seems like you yearn for Java checked exceptions ;-). Goran.
From: Goran on 24 Jun 2010 08:14
On Jun 24, 1:58 pm, Hector Santos <sant9...(a)nospam.gmail.com> wrote: > Case in point, I/O, there is a pretty well define set of highly > probably errors and then ones that are common to general I/O. > > For fopen, for example, some people will view > > not found > bad input (bad path) > locked error > sharing error > > are natural errors with a high expectation, with a certain level of > natural recovery, while others are global and not highly recovery: > > out of memory > out of disk space > hard drive problem > > Again, don't focus on the attempts for details mentioned, but the > generalization I am making. Yeah, I've heard (a variation of) that reasoning before, and I don't like it ;-). Here's why: I believe that it creates a hybrid system for error propagation that is ultimately harder to work with than clear- cut error-return (or clear-cut exceptions). For example, you still have to take care about making code exception safe, and you still have to know where are "if" functions. Sure, you might want to something differently about your "natural" errors. With exceptions, that translates to catching particular exception type here and there, and taking corrective action (or, in error-return code, taking said corrective action in a rare "if" (but! drawback is that there are zillions of "if"s in error-return, so the "interesting" ones are harder to spot ;-)). So there, IMHO, you don't gain much by having an "if" being simpler than a try/catch. Goran. |