Prev: Deriving from a class derived from a CDialog
Next: How to show underlined menu shortcut letters by default for a contextmenu ?
From: Joseph M. Newcomer on 25 Jun 2010 03:23 See below... On Wed, 23 Jun 2010 19:48:26 -0400, Hector Santos <sant9442(a)nospam.gmail.com> wrote: >Joseph M. Newcomer wrote: > >> See below... >> On Wed, 23 Jun 2010 15:29:21 -0400, Hector Santos <sant9442(a)nospam.gmail.com> wrote: >> >>> I don't know Joe. You make me feel like everything I did was wrong. :) >>> >>> I'm was APL programmer, tranformation, black boxes, stacking of such >>> concept was the way I thought and if you do it all in one line, the >>> better. >> **** >> APL was not pure FP, because there was always output. As soon as you have a side effect, >> you move outside the original FP model. > > >FP by definition is either dyadic or monadic functional programming, >and nothing more. After 30 years, its news to me for anyone to >suggest the idea that it wasn't a "pure" functional programming >language which by itself isn't well defined or if you only want to >based it on a lambda adaptation or define only in more recent history >or research to the evolving FP paradigm. :) **** I have not used APL since 1968. But while the core APL language was pureful functional, there is always that nasty little part where output was produced. And that's where the FP "side-effect-free" paradigm breaks down. That output is a side effect. LISP, a language I used for many years, was in its purest form FP, but I had to print output, and write to disk. Also, I had to manage internal state of my workspace, and that also violated the FP model (LISP suffered from a number of serious failures, not the least of which was the inability to specify modules and interfaces, so I had to build an entire source management system inside my workspace to handle the hundreds and hundreds of functions and impose some rationale on them) > >> *** >>> The concept of Errors was secondary and an side issue really and >>> should be never be part of the overall FP framework. I mean, of >>> course, you have to design for it, but its a side issue when it comes >>> to FP. >> **** >> FP always made the assumption that input data was perfect, and algorithms were perfect, >> and therefore execution would always run to completion successfully. > > >Or to more exact, perfectly aligned "transformations." > >> When APL hit an error, it just stopped dead. The code terminated, and told you why. Of >> course, being a write-only language, it was really hard to decipher what you were doing. > > >Well sure, maybe for most laymans but not for the APL purest. Most >good APL programmers thought out the solution first in their mind. I >always said it helped me as I learned other languages, I had an APL >mindset when I writing equivalent functionalities. **** This did not change the fact that it was a write-only language, or that it was hard to read an APL program and deduce what it was trying to do. This is quite different from "thinking through" a program which worked for perfect data input. **** > >> [I often have said that the reason I passed one of the PhD qualifiers was that I found a >> bug in the APL example, proving the rho operator would fail with an error. I then said >> "You probably intended to write..." and showed the corrected code, and then I answered the >> question] >> **** > > >You are/was/were certainly a character. :) > >>> And I guess even for native images there is an RTE - the OS and its >>> Doctor Watson recordings. >>> >>> So for me, as I am learning .NET (and I have used .NET here and there >>> in the past 10 years, but never as deeply as I am now), I think the >>> overall issue for me, is learning what the possible error conditions >>> with the rich .NET library. Because until you become an expert in it, >>> all you have to save you is using exception traps. >> **** >> I've been fairly generous with try/catch blocks in environments that resembled what .NET >> now is. It really is a pain. >> **** > > >In C/C++ code, I only used exceptions trap because of the >implementation of classes where you have no other choice. > >In .NET, you really have no CHOICE :) > >>> I like .NET, I think it really helps people in dealing with both code >>> syntax and also whats NOT possible or even if intellisense doesn't >>> tell you, its internal global catch all - will. :) >> *** >> Is Intellisense actually Intelli*sense* in .NET? Certainly in C++ it is at best >> Intelli*nonsense*. I've done some C# code, I like the language, but none of my clients >> have the slightest interest in it. >> joe > > >In all honestly, without IntelliSense in VS2010, I would be having a >much tougher time or less productive time looking up things. *** Intellinonsense has several design defects. For example, it uses the raw API names (the A and W suffixed names) instead of the official API names; when I get to a bitfield, it gives me a UINT or DWORD instead of a list of options, and so on. I find this completely useless. **** > >I can't compare with VS98 and VS2005 because I never depended in it >before. I turned it off because it was awfully slow for me. > >But in VS2010, I am truly impressed with the IDE and IntelliSense >helps in almost everything, including only exposing or not exposing >whats possible or not within block contexts and namespace. Its not >slow at all for me, and I really love how it automatically jumps to >the proper selection of constructors, variables, types, etc, that make >sense for the new instance, construct or blocks. > >I have yet to see anything that has yield a negative impression or bad >rap for IntelliSense or VS2010 itself. The help is better, F1 gives >you a suggestion, but I use the speedy Chrome as my MSDN help. Its >wonderful. I'm having a blast with VS2010 and can't wait to begin >migrating my products over in earnest. Maybe then I may see issues. >But not yet. :) *** I found the VS2010 help to be among the worst products (if you can dignify anything this bad with the term "product") ever delivered; it clearly was designed by people who knew nothing about how end users actually used help. And the new UI that was released doesn't actually work. So I find the help system completely unusable. joe *** Joseph M. Newcomer [MVP] email: newcomer(a)flounder.com Web: http://www.flounder.com MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Joseph M. Newcomer on 25 Jun 2010 03:28 See below... On Wed, 23 Jun 2010 20:10:57 -0400, Hector Santos <sant9442(a)nospam.gmail.com> wrote: >Hector Santos wrote: > >>> *** >>> Is Intellisense actually Intelli*sense* in .NET? Certainly in C++ it >>> is at best >>> Intelli*nonsense*. I've done some C# code, I like the language, but >>> none of my clients >>> have the slightest interest in it. >>> joe >> > >Joe, miss this one. > >So far, I all did was C#, a little VB.NET and a few C++.NET and >Intellisense was wonderful here. I beginning to really like C#. **** A friend who was deeply anti-Microsoft (as in "Microsoft can never produce anything valuable") was forced to move from Java to C# by an internal change in policy where he worked. He finally confessed, "C# is Java done right". That is a *big* admission from someone of his prejudices. **** > >I don't know yet what will happen when I begin to recompile my C/C++, >MFC products with VS2010. **** I haven't hit problems yet. But I've taken only a couple major projects across; most of my projects that I've had time to work on are small. My clients are still requiring I work in VS2003 or VS2005; only the most advanced are using VS2008. So only my personal projects are in the most recent versions of VS. *** > >The plan is to first keep the main RPC application server in C/C++ and >begin moving the RPC clients to .NET, especially the GUI clients. > >I think MFC projects can be recompiled into .NET by adding Window >Forms, etc, or as soon as you add a reference to a .NET component, it >comes a .NET applet. **** Haven't done that yet. joe **** Joseph M. Newcomer [MVP] email: newcomer(a)flounder.com Web: http://www.flounder.com MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Goran on 25 Jun 2010 05:47 On Jun 24, 5:14 pm, Hector Santos <sant9...(a)nospam.gmail.com> wrote: > Goran wrote: > > Now, supposing that you have several places where you might get into a > > particular situation, and after seeing the error in your log, you > > don't know where that place is (if you will, you know the line, but > > it's important t know where did you come from to it). Then, you have > > two possibilities: > > > 1. have "debug" logging, turn it on and look there to see where things > > start to fall apart. Combine with error log and there you are. > > 2. "enhance" original error while unwinding the stack (add "context" > > if you will). > > Or use trace tags. :) What's that? Honest question, I don't know, and google-fu fails me. > I think maybe we are agreeing on the same issues. Trust me, this is > not an issue for me. Flows are not broken, exceptions are truly the > "exception" and not the rule and I have implemented different ideas > different ways, some simple, some more detailed for consumer usage. > So while I may say/write one thing, its not the be taken as its the > only way. :) > > The only point I was making is that using a catch all, to me, is > generally more useful until you can chime in on specifics. Note I am > not speaking of an external the code block catch alls, but at the same > level. The external catch all only help you under debug mode since it > has source line numbering. > > >> Not quite sure if I follow, and if I did, I would not be among the > >> 90%. > > > I really have to press you here: so what code do you have after a > > failed call? > > Its covered. its not ignored goran. :) Yeah, I didn't want to say that. Instead, I wanted to press you to look into the following in your own code: what does your code do after the "if (func(params)"? Chances are, nothing meaningful. So had that function been void+exception, the "if" would have disappeared altogether. > > Provide some examples, and I am pretty confident that, > > > even if you used exceptions, you could get what you need pretty easily > > (that is, even if you "handle" errors, it's trivial to do what you do > > either way, exceptions or error-return). > > Sure, I have both. A good example was a NNTP date/time parser. The > syntax is: > > yymmdd hhmmss [GMT] RFC 977 > [yy]yymmdd hhmmss [GMT] RFC 3977 (replaces RFC 977) > > I ended up with two parsing overloading functions > > public bool GetNNTPDateTime(string sdt, out DateTime dt) > public DateTime GetNNTPDateTime(string sdt); > > so I can use the first overload: > > public bool onNEWGROUPS(ClientData ctcp, string args) > { > DateTime dtSince; > if (!GetNNTPDateTime(args, dtSince)) { > ctcp.SendLog("501 Invalid date/time\r\n"); > return true; // RETURN ONLY FALSE TO BREAK CONNECTION > } > .... > return true; > } > > or I can use the exception overload version: > > public bool onNEWGROUPS(ClientData ctcp, string args) > { > DateTime dtSince; > try > { > dtSince = GetNNTPDateTime(args) > } > catch (Exception ex) > { > ctcp.SendLog("501 {0}\r\n",ex.Message); > return true; // RETURN ONLY FALSE TO BREAK CONNECTION > } > .... > return true; > } OK, that's good enough as context. So you have "bool GetNNTPDateTime" (lowest call level), then "bool onNEWGROUPS", and then, (I'll presume, for sake of the example) the final "processing" function that has to respond to something out of the scope of discussion, and that can't throw. So you have (rough sketch): void Process(stuff) { ... if (!onNewsgroup(...)) { BreakConnection(); // I got this from RETURN ONLY FALSE TO BREAK CONNECTION return; // (nothing else to do) } ... } Now... Imagine that these are were void functions, and that your "need to break the connection" was handled e.g. like this: class NonBreakingProcessingError : Exception { // Can use this to tell client what went wrong. } Now... GetNNTPDateTime uses that to signal "input" errors. void Process(stuff) { try { .... onNewsgroup(whatever); .... } catch(Exception e) { // Nothrow zone here, hence yet another try-catch :-( try { string err; if (GetNonBreakingErrorInfo(e, err)) ctcp.SendLog(err); else BreakConnection(); } catch(Exception e) { WeAreReallyDoomed(); /*OOM? Run GC?*/} } } bool GetNonBreakingErrorInfo(Exception e, out string err) { if (e is NonBreakingProcessingError) { err = e.Message; return true; } return false; } (Or a variant thereof, e.g. you might decide to use INonBreakingError interface, that allows you to mix-in and simplify GetNonBreakingErrorInfo...) In other words, you can do what you need to do with exceptions, but you need to cover your need to break the connection in some "bad" cases. You don't need to do ctcp.SendLog right at the place of the error - __there__ is the error of your ways ;-) (I know, I know, you said that you like it that way, and I don't want you to change your ways, but it's really this: with exceptions, things change, and that way of yours is much less good with them...) BTW: just as I said, onNewsgroup doesn't really do much after failed GetNNTPDateTime. So you can just as easily do nothing about it's failure in onNewsgroup, but still treat it further up. In your case, the trick is to collect your "non-connection-breaking" errors correctly inside that final catch. I know, in "real world", things will get more complicated, but overall, I am adamant that code structure does need to change. e.g. GetNonfatalErrorInfo may grow, because non-connection-breaking errors will be numerous. But you do have a lot of wiggle room there (e.g. interface idea etc). I also know that in this simple example, the benefit of using exceptions isn't there (a couple of "if"s are simpler, aren't they?) but the thing is, exactly in the real world, these "if"s accumulate really quickly, much faster than try/catch statements. Just imagine that you apply the above principles of mine to 4-5 additional "if" calls. Goran.
From: Joseph M. Newcomer on 25 Jun 2010 13:40 See below... On Thu, 24 Jun 2010 06:54:38 -0700 (PDT), Goran <goran.pusic(a)gmail.com> wrote: >On Jun 24, 2:57�pm, Hector Santos <sant9...(a)nospam.gmail.com> wrote: >> > Of course not. For the most part, you just do >> >> > if (!myfunc(params)) >> > � return false; >> >> > (or equivalent thereof) >> >> Could be, sure. �For me, for example, logging functions: >> >> � � FILE *fv = fopen(filename, "at"); >> � � if (fv) { >> � � � �fprintf(fv,whatever); >> � � � �fclose(fv); >> � � } > >Yes, this is a (well known? perhaps) issue when going exceptions. You >need to turn things on their heads somewhat. Supposing that you throw, >whatever happens, somewhere down the line you have to report this >error. The best way to do this is to have nice "original" error info. >In this case, that's relatively easy, because you have file name and >errno - all is there. So for logging, there's, again, nothing to do if >you use exceptions: error will propagate to somewhere up the stack, >and.. Surely you won't forget to log it. But! But... It's >__essential__ not to lose sight of the original error and to be >comprehensive with error info. **** This is why exceptions are so much better than simply doing "return FALSE", because the return FALSE says "I failed, and I'm not going to tell you why, so deal with it", and that doesn't help field support in the slightest. All you get back from the user was "I get this dialog box that says something failed" and when you ask what you get "It said something about memory, or maybe disk". This is why we get completely stupid error messages in Microsoft programs, for example, "File write error" instead of "File write error: access denied" or "File write error, disk full", or worse still, that piece of stupidity in the linker that says "Unable to write xxxx.pdb. Make sure you have access to the drive and directory, and sufficient space on the disk" when what it should say is "Unable to write xxxx.pdb. Access denied". Because the TRUE explanation is "You have WinDbg open and it is holding the symbol table open, and we can't rewrite it", but that does not appear ANYWHERE, and the mistranslation of the message confuses people (note: I teach a course in driver development, and the students get this message at least once per student group, and EACH group is clueless what to do because the text of the message is so misleading! There is the sad case of Giving Too Much Information, especially when you give a LOT of information and NONE of it relates the actual source of the problem!) Note: the ONLY acceptable message is File Write Error <file name here> <FormatMessage of error code here> Exceptions allow you to display that information at any level of interception; return FALSE carefully destroys the information. Note you can't depend on GetLastError because I've found that some destructors (notably, destructors of Automation interface objects) change the value of GetLastError! *** > >Now, supposing that you have several places where you might get into a >particular situation, and after seeing the error in your log, you >don't know where that place is (if you will, you know the line, but >it's important t know where did you come from to it). Then, you have >two possibilities: **** I make it a policy to NEVER, EVER issue the same error message from two places in my program. I can tell, immediately, from the error text (whether in a MessageBox or logged to the Event Log) exactly where it came from. Doing other than this leads to serious field support issues. You don't need debug logging, and you don't need anything fancy; every source of an error (and consequently, every exception thrown) contains this information. In some cases, my exceptions have space for _T(__FILE__) and __LINE__ so I know who threw it (doesn't help the end user, but helps tech support and me tremendously!) Usually, I log the error at the site and THEN throw an exception. **** > >1. have "debug" logging, turn it on and look there to see where things >start to fall apart. Combine with error log and there you are. >2. "enhance" original error while unwinding the stack (add "context" >if you will). > >At any rate, I am pretty certain that exceptions won't really stop you >from getting the desired result. But one has too stop with error- >return thinking first (don't be mad at me, but I believe you can't let >that go). Instead, you have to think this way: any given line can >throw, bar those specifically crafted not to (and they are rare and >hence +/- easy to spot). Next, you start thinking in terms of >exception-safety guarantees for any code snippet/function. For >example, any resource allocation might need "protection". **** Some error conditions should not occur, but will because they are outside your control (user deletes a critical file, the disk gets full, etc.) If the end user knows the error is "Disk full", then the end user can fix it without a tech support call. If the error says "File write error" then tech support has to figure out that this might be a disk full condition and then ask the user to check on the disk space. At this point, you have a $50-$100 cost in tech support. So the idea is, don't let that happen. And even if the end user is not sophisticated enough, the situation often falls on the team manager, site support manager, etc. who ARE more sophisticated, and can make better sense of an informative message ("just the facts, ma'm" no interpretation, unlike the stupid linker error message that erroneously attempts to come to a conclusion of the cause). But you want to avoid a tech support call! **** > >> >> but there are cases where in my more elaborate class based logging >> class, where there is rotating of files, etc, there are some error >> checking, including a general catch all for the valist. >> >> > 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. >> >> Not quite sure if I follow, and if I did, I would not be among the >> 90%. > >I really have to press you here: so what code do you have after a >failed call? Provide some examples, and I am pretty confident that, >even if you used exceptions, you could get what you need pretty easily >(that is, even if you "handle" errors, it's trivial to do what you do >either way, exceptions or error-return). Here's my bet: most of the >time, you have error cleanup, for which you should use RAII in e.g. C+ >+, or "using" in C#, or you have logging (see above about that). In >rare places, you have "corrective" action. But I bet you that these >are __rare__. *** A failed call should be handled at the failure site. Now, the next question is, how do I recover from this? The answer is not something the failure site should have to worry about. It reports the failure and Goes On With Life. Whether it does return [FALSE; 0; -1; NULL] or throw [exception name here], it is punting the recovery to a Higher Power. So now we start arguing aesthetics. joe **** > >Goran. Joseph M. Newcomer [MVP] email: newcomer(a)flounder.com Web: http://www.flounder.com MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Hector Santos on 25 Jun 2010 17:54
Goran wrote: > On Jun 24, 5:14 pm, Hector Santos <sant9...(a)nospam.gmail.com> wrote: >> Goran wrote: >>> Now, supposing that you have several places where you might get into a >>> particular situation, and after seeing the error in your log, you >>> don't know where that place is (if you will, you know the line, but >>> it's important t know where did you come from to it). Then, you have >>> two possibilities: >>> 1. have "debug" logging, turn it on and look there to see where things >>> start to fall apart. Combine with error log and there you are. >>> 2. "enhance" original error while unwinding the stack (add "context" >>> if you will). >> Or use trace tags. :) > > What's that? Honest question, I don't know, and google-fu fails me. A technique to pepper your code with functional labels for your own help or end-user support. I could explain many examples but the closest example is .NET Debug command: Debug.WriteLine(object value [,string category]); which if the category string is passed, it will display in the debug console: Catogory: value The category string is a trace tag for your quick dissemination, but you can employ it for release code to in log files, session information, etc, exception/error displays. I deem it a important programming and support concept. It helps :) Regarding the rest of your post, if I follow your main point, its all a matter of how you wish to implement your application or protocol. For example, this internet client/server protocol is a solid framework used for a long time, the dispatch handler expects one result true to continue false to force ending the connection But by tradition, most, if not ALL internet protocols ASSUME disconnects are client driven, i.e. QUIT. This is important for example the POP3 protocol which the standard says if the client does not issue the QUIT command, then the POP3 server SHOULD assume an aborted session and SHOULD NOT update any mail pointers for mail that was downloaded. The expected explicit QUIT command informs the server to move into the update mode to update the user completed downloaded information. No QUIT, no Update. In the same vain, the server MUST NOT abort clients unless its a malicious or errant client in action. i.e, too many BAD command. So our protocol model is based on these long established functional protocol requirements. Now, that said, there are models where you can THROW an exception that the DISPATCHER catches. But you have to be careful for this because if any handler (or delegate) is doing a catch all, then this can throw off the flow. So in his case, it needs to be very explicit with specific exception traps so that others can fall thru the chain. In fact, the Thunderbird SMTP mail client had this very problem back in 2000 which I reported and help fixed after downloading the source code. https://bugzilla.mozilla.org/show_bug.cgi?id=62836 If I recall, TBIRD threw an exception to disconnect a session as a quick way to to "jump" to the dispatcher and end the session. It didn't bother to send the QUIT command. But if I recall, the logic was there to send it, it just never got to it because of the exception used to end the session. SMTP also "technically" requires a QUIT command to signify a completed session. If I recall, it was simple to just move some code around to make sure a QUIT was always sent before the session was disconnected. -- HLS |