Exception handling?

  • Follow


In my below foobar first attempt to try exception handling I don't understand
the following aspects:  (my code at bottom after these framework pastes)

1. I must not be doing something correct because even though both
my CATCH and AND_CATCH call stuff on return that appears to be 
deleting the exception and taking care of various cleanup. 

// abbreviated Step thru pastes
//---------------------------------------
void AFXAPI AfxTryCleanup( )
{
   ......
   .....
  // delete current exception
  ASSERT(pLinkTop != NULL);
  if (pLinkTop->m_pException != NULL)
    pLinkTop->m_pException->Delete( );
 .....
 .....
}
// and later
CString::~CString()
 //  free any attached data
{
  ....etc etc
}
//--------------------------------------
* * when the exception returns back to document caller I don't see this 
* *     getting executed, 

  if (!pDocument->OnNewDocument())
  {
    // user has been alerted to what failed in OnNewDocument
    TRACE0("CDocument::OnNewDocument returned FALSE.\n");
    if (bCreated)
      pFrame->DestroyWindow();    // will destroy document
    return NULL;
  }
  .....
  .......
// Instead I see this down the road,
 
CDocument* CWinApp::OpenDocumentFile(LPCTSTR lpszFileName)
{
 ASSERT(m_pDocManager != NULL);       
    //* *And lpszPathName still = TheFileNameItriedToOpen ? * *
 return m_pDocManager->OpenDocumentFile(lpszFileName);
}
//* *
So if I save my document after code turns app back over to me I overwrite 
the file that I could not open ? So there must be more " I " have to do, or something 
different if I have it all wrong out of the shute.

2. Also from the docs I have read I got the impression that by putting THROW_LAST( );
    at the end of my CATCH( CUserException, e ) that it would forward the exception
    to my AND_CATCH( CException, e ) but experimentation shows that does not
    happen, so I missed something there. But anyhow both exceptions seem to pass
    to clean up code on return so question 2 is only a curiousity. Question 1 is my
    main concern.

=== foobar attempt below ====

void CFileHandlingDoc::Serialize(CArchive& ar)
{ 
 if (ar.IsStoring())       
   { 
      ar << FileID;    // DWORD
     ar << VerData.Ver << VerData.CpyRt << VerData.Corp;  
     ar.SerializeClass(RUNTIME_CLASS(CMapStringToString)); 
     ExpMap1.Serialize(ar);    
   }                                         
 else               
   { 
     CString E;
     TCHAR szErrMsg[255];
     TRY
      {
        ar >> FileID;                 
        if (FileID != 0x1234ABCD)
          { // FileID mismatch                         
            AfxThrowUserException( );
          }
        ar >> VerData.Ver >> VerData.CpyRt >> VerData.Corp;
        ar.SerializeClass(RUNTIME_CLASS(CMapStringToString)); // WriteClass CmStS's data
        ExpMap1.Serialize(ar);    // CMapStringToString's keys and values
         
      }
     CATCH( CUserException, e )
      {
        E = _T("BAD FileID, RB from inside CATCH\n");
        AfxMessageBox( E );
        return;
      }
     AND_CATCH( CException, e )
      {
        // For other exception types, notify user here.
        e->GetErrorMessage(szErrMsg, 255);
        E = _T("RB from inside AND_CATCH\n");
        E += szErrMsg;
        AfxMessageBox( E );
        return;   
      }
     END_CATCH
        // No exception thrown.
   }
}                     


0
Reply RB 6/21/2010 4:13:13 PM

See below...
On Mon, 21 Jun 2010 12:13:13 -0400, "RB" <NoMail@NoSpam> wrote:

>In my below foobar first attempt to try exception handling I don't understand
>the following aspects:  (my code at bottom after these framework pastes)
>
>1. I must not be doing something correct because even though both
>my CATCH and AND_CATCH call stuff on return that appears to be 
>deleting the exception and taking care of various cleanup. 
****
You should avoid these obsolete macros.  They were created before the C++ compiler
correctly implemented (or implemented at all) the C++ exception syntax.
****
>
>// abbreviated Step thru pastes
>//---------------------------------------
>void AFXAPI AfxTryCleanup( )
>{
>   ......
>   .....
>  // delete current exception
>  ASSERT(pLinkTop != NULL);
>  if (pLinkTop->m_pException != NULL)
>    pLinkTop->m_pException->Delete( );
> .....
> .....
>}
>// and later
>CString::~CString()
> //  free any attached data
>{
>  ....etc etc
>}
>//--------------------------------------
>* * when the exception returns back to document caller I don't see this 
>* *     getting executed, 
>
>  if (!pDocument->OnNewDocument())
>  {
>    // user has been alerted to what failed in OnNewDocument
>    TRACE0("CDocument::OnNewDocument returned FALSE.\n");
>    if (bCreated)
>      pFrame->DestroyWindow();    // will destroy document
>    return NULL;
>  }
>  .....
>  .......
>// Instead I see this down the road,
> 
>CDocument* CWinApp::OpenDocumentFile(LPCTSTR lpszFileName)
>{
> ASSERT(m_pDocManager != NULL);       
>    //* *And lpszPathName still = TheFileNameItriedToOpen ? * *
> return m_pDocManager->OpenDocumentFile(lpszFileName);
>}
>//* *
>So if I save my document after code turns app back over to me I overwrite 
>the file that I could not open ? So there must be more " I " have to do, or something 
>different if I have it all wrong out of the shute.
>
>2. Also from the docs I have read I got the impression that by putting THROW_LAST( );
>    at the end of my CATCH( CUserException, e ) that it would forward the exception
>    to my AND_CATCH( CException, e ) but experimentation shows that does not
>    happen, so I missed something there. But anyhow both exceptions seem to pass
>    to clean up code on return so question 2 is only a curiousity. Question 1 is my
>    main concern.
>
>=== foobar attempt below ====
>
>void CFileHandlingDoc::Serialize(CArchive& ar)
>{ 
> if (ar.IsStoring())       
>   { 
>      ar << FileID;    // DWORD
>     ar << VerData.Ver << VerData.CpyRt << VerData.Corp;  
>     ar.SerializeClass(RUNTIME_CLASS(CMapStringToString)); 
>     ExpMap1.Serialize(ar);    
>   }                                         
> else               
>   { 
>     CString E;
>     TCHAR szErrMsg[255];
>     TRY
****
Use try (lower case)
>      {
>        ar >> FileID;                 
>        if (FileID != 0x1234ABCD)
****
Why is this a hardwired literal?  Why did you not do

const DWORD CURRENT_FILEID = 0x1234ABCD;
?
****
>          { // FileID mismatch                         
>            AfxThrowUserException( );
****
I would have done
	throw new CWrongFileIDException(FileID)
where I would have defined a specific exception that did exactly what I wanted:

class CWrongFileIDException : public CException {
    public:
          DWORD GetFileID() { return fid; }
          CWrongFileIDException(DWORD fileid) { fid = fileid; }
    protected:
          DWORD fid;
};

You should not "hijack" some other exception to mean other than what precisely happened!
****
>          }
>        ar >> VerData.Ver >> VerData.CpyRt >> VerData.Corp;
>        ar.SerializeClass(RUNTIME_CLASS(CMapStringToString)); // WriteClass CmStS's data
>        ExpMap1.Serialize(ar);    // CMapStringToString's keys and values
>         
>      }
>     CATCH( CUserException, e )
****
Take a look at CUserException (by the way, you should not use built-in exceptions like
this)  Instead, you should write your own exception (like above)

then to throw it you would do

throw new CWrongFileIDException(FileId);

Get rid of CATCH and write
	catch(CUserException* e)
or, if you define a CRBException, use
	catch(CWrongFileIDException * e)

Note that the documentation of AfxThrowUserException does NOT state what kind of exception
it throws, and it says that it throws an exception to "stop an end-user operation".  But
if you read the actual code, it CLEARLY throws a CUserException*. For most exceptions, the
documentation is at best confusing, and it is usually merely erroneous.  In this case, it
is nonexistent.  So why did you think it throws a CUserException when you have no
documentation to rely on?  If it doesn't tell you what it does, you don't know.  So in
that case, "trust the source, Luke".  I read the documentation, and at least in the
version I have, it says absolutely NOTHING about what is thrown.  And there is no reason
to suspect that Microsoft would not change this in the future.  So why are you relying on
an effectively completely undocumented function?
****
>      {
>        E = _T("BAD FileID, RB from inside CATCH\n");
>        AfxMessageBox( E );
>        return;
****
Query: why are you putting an English language message in SOURCE code?  That's what
STRINGTABLEs are for!

Query: Why did you declare the variable E so far from where it is used?  It should be
written, if you want to keep the really bad idea of English strings, as

         CString E = _T("...");

that is, you should never declare a variable in a scope wider than it needs to exist!

And for that matter, why did you have to declare a CString for AfxMessageBox?  If you want
to keep the Really Bad Idea, do 

	AfxMessageBox(_T("..."));

don't introduce variables you don't need, and NEVER declare them with a scope larger than
you need!

Note that AfxMessageBox allows you to give the UINT of a STRINGTABLE ID, so if you are
using a literal string, you would not say anything more than
	AfxMessageBox(IDS_BAD_FILE_ID);

You should also do
	e->Delete();
to handle the case where the exception was thrown with 'new'
****
>      }
>     AND_CATCH( CException, e )
****
Due to terminal brain damage on the documentation team, they keep erroneously claiming,
for example, that some operation "Throws a CFileException" or something like that, when
the TRUTH is that they throw a CFileException*.   This is slovenly documentation, and I've
been complaining about it for years.  As far as I can tell, NO exception in MFC is EVER
other than a derived class of CException*, not CException.  So the documentation lies in
its teeth.

Get rid of tne AND_CATCH, and replace it with
	catch(CFileException * e);
****
>      {
>        // For other exception types, notify user here.
>        e->GetErrorMessage(szErrMsg, 255);
****
szErrMsg should not have a scope outside these braces.  Why is it declared anywhere else?
Same applies to E.  Why did you not write
	TCHAR szErrMsg[255];
	e->GetErrorMessage(szErrMsg, _countof(szErrMsg));
?

If you are going to use a size, either use _countof EVERYWHERE to reference it (if it is a
compile-time constant array) or a symbolic length name
****
>        E = _T("RB from inside AND_CATCH\n");
>        E += szErrMsg;
>        AfxMessageBox( E );
****
Don't forget to do
	e->Delete();
****
>        return;   
>      }
>     END_CATCH
****
There is no need for END_CATCH.  These macros are obsolete and should not be used in
modern programming.  They are leftovers from the 16-bit C++ compiler of 1993 or so, and
were effectively obsolete by (if I remember correctly) VS 4.2.  Certainly by VS6.
			joe
****
>        // No exception thrown.
>   }
>}                     
>
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/21/2010 5:16:23 PM


> You should avoid these obsolete macros.  They were created before the 
> C++ compiler correctly implemented (or implemented at all) the C++ 
> exception syntax.
> ****
> Use try (lower case)
>>      {
>>        ar >> FileID;                 
>>        if (FileID != 0x1234ABCD)
> ****

Ok, noted, you gave me so much to work with I will have to get
back with you on most of this Actually what I am most concerned 
with right now is learning all of what you just gave me. 
   I stepped thru my doc return code again and it appears that is not
currently doing what I had hoped. I realize if I click SAVE it is going to 
save whatever new document data in currently in the members. What I 
was hoping for was that the exception code would void out the current 
lpszFileName doc variable so that at least when I click save it would 
prompt me for a filename instead of just overwriting what is in the 
lpszFileName.

> Why is this a hardwired literal?  Why did you not do
> const DWORD CURRENT_FILEID = 0x1234ABCD;
> ?
> ****

Ugh maybe because I am a dummy and have not learned any better?

>>          { // FileID mismatch                         
>>            AfxThrowUserException( );
> ****
> I would have done
> throw new CWrongFileIDException(FileID)
> where I would have defined a specific exception that did exactly what 
> I wanted 
> class CWrongFileIDException : public CException {
> public:
>          DWORD GetFileID() { return fid; }
>          CWrongFileIDException(DWORD fileid) { fid = fileid; }
>    protected:
>          DWORD fid;
> };
> 
> You should not "hijack" some other exception to mean other than what 
> precisely happened!
> ****

Ok give me some time to work with this.

> ****
> Query: why are you putting an English language message in SOURCE code?  
> That's what STRINGTABLEs are for!

This was only just for "me" to see if / when it was actually called.
 
> Query: Why did you declare the variable E so far from where it is used?  
> It should be written, if you want to keep the really bad idea of English strings, 
>      CString E = _T("...");
> that is, you should never declare a variable in a scope wider than it needs to exist!

The stuff about where to declare the vars I really just have not gotten that far yet, 
but appreciate it and will try to incorporate it into my current attempt to learn 
exceptions. 

> And for that matter, why did you have to declare a CString for AfxMessageBox? 

Well for the one I did not have to, but I got into the CString originally in order
to copy the strings together

 e->GetErrorMessage(szErrMsg, 255);
        E = _T("RB from inside AND_CATCH\n");
        E += szErrMsg;
// Again the English is just for me to "see" when it was called.

> .....
> You should also do
> e->Delete();
> to handle the case where the exception was thrown with 'new'
> ****

Ok I will have to digest these new items and look in some other docs for this.
Thanks.
0
Reply RB 6/21/2010 7:21:51 PM

See below...
On Mon, 21 Jun 2010 15:21:51 -0400, "RB" <NoMail@NoSpam> wrote:

>
>
>> You should avoid these obsolete macros.  They were created before the 
>> C++ compiler correctly implemented (or implemented at all) the C++ 
>> exception syntax.
>> ****
>> Use try (lower case)
>>>      {
>>>        ar >> FileID;                 
>>>        if (FileID != 0x1234ABCD)
>> ****
>
>Ok, noted, you gave me so much to work with I will have to get
>back with you on most of this Actually what I am most concerned 
>with right now is learning all of what you just gave me. 
>   I stepped thru my doc return code again and it appears that is not
>currently doing what I had hoped. I realize if I click SAVE it is going to 
>save whatever new document data in currently in the members. What I 
>was hoping for was that the exception code would void out the current 
>lpszFileName doc variable so that at least when I click save it would 
>prompt me for a filename instead of just overwriting what is in the 
>lpszFileName.
****
If you want your exception code to clear this variable, you will have to do that
explicitly.  Note that if this value is set AFTER the serialization call, because you are
handling the excepiton internally and not throwing it, there is zero hope that you will be
able to deal with this.  Instead, you will have to add a handler for operations like
File::Save, you will have to put an exception handler in that code, you will have to have
your very own generic exception class (not CUserException), something like
CMySerializeException, of which CWrongFilieIDException is but one of the many possible
derived classes, and you will have to do a 
	throw;
instead of
	e->Delete()
so your exception is seen outside the serialize handler.

WHat I did to implement a parser was to have a CSyntaxException class and derive from it
such exceptions as CUndefinedVariableException, CWrongSymbolException (e.g., finding a
variable when an operator is expected), CMissingParenthesisException,
CExtraParenthesisException, and things like that.  CTypeMismatchException.
CMissingSemicolonException (when I was pretty sure that was what was wrong).
CIllegalStructMemberException.  and so on and so on.

Never be afraid to create your own classes of exceptions when needed.  Never "hijack" some
generic class.  Make sure that every exception has useful information in it so you can
make a report (I included file name, line #, and offset-into-line in CSyntaxException, and
for things like CWrongSymbolException I had a placeholder for the entity I expected, so I
would do
	throw new CWrongSymbolException(file, line, offset, IDS_EXPECTED_VARIABLE_NAME);

class CWrongSymbolException: public CSyntaxException {
	public:
	    CWrongSymbolException(const CString & file, long line, int offset, UINT Id) :
                           CSyntaxException(file, line, offset) {
		symid = id;
                           CString GetErrorString() {
		CString where = CSyntaxException::GetErrorString(); // filename(line)
                                CString msg;
                                msg.LoadString(IDS_EXPECTED);
                                CString what;
	 	what.LoadString(symid);
                                msg.Format(what); //filename(line): error: expected <what>
                               return msg;
                             }
	      protected:
		UINT symid;
};

Note that the explanation is a STRINGTABLE entry so I'm language-independent.

Note, however, that in your code, you catch and dismiss the exception entirely within the
Serialize() function, therefore, as far as anyone OUTSIDE that funtion is concerned, the
exception never happened!  So the assumption is that the operation completed successfully!
				joe
*****
>
>> Why is this a hardwired literal?  Why did you not do
>> const DWORD CURRENT_FILEID = 0x1234ABCD;
>> ?
>> ****
>
>Ugh maybe because I am a dummy and have not learned any better?
>
>>>          { // FileID mismatch                         
>>>            AfxThrowUserException( );
>> ****
>> I would have done
>> throw new CWrongFileIDException(FileID)
>> where I would have defined a specific exception that did exactly what 
>> I wanted 
>> class CWrongFileIDException : public CException {
>> public:
>>          DWORD GetFileID() { return fid; }
>>          CWrongFileIDException(DWORD fileid) { fid = fileid; }
>>    protected:
>>          DWORD fid;
>> };
>> 
>> You should not "hijack" some other exception to mean other than what 
>> precisely happened!
>> ****
>
>Ok give me some time to work with this.
>
>> ****
>> Query: why are you putting an English language message in SOURCE code?  
>> That's what STRINGTABLEs are for!
>
>This was only just for "me" to see if / when it was actually called.
> 
>> Query: Why did you declare the variable E so far from where it is used?  
>> It should be written, if you want to keep the really bad idea of English strings, 
>>      CString E = _T("...");
>> that is, you should never declare a variable in a scope wider than it needs to exist!
>
>The stuff about where to declare the vars I really just have not gotten that far yet, 
>but appreciate it and will try to incorporate it into my current attempt to learn 
>exceptions. 
>
>> And for that matter, why did you have to declare a CString for AfxMessageBox? 
>
>Well for the one I did not have to, but I got into the CString originally in order
>to copy the strings together
>
> e->GetErrorMessage(szErrMsg, 255);
>        E = _T("RB from inside AND_CATCH\n");
>        E += szErrMsg;
>// Again the English is just for me to "see" when it was called.
>
>> .....
>> You should also do
>> e->Delete();
>> to handle the case where the exception was thrown with 'new'
>> ****
>
>Ok I will have to digest these new items and look in some other docs for this.
>Thanks.
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/21/2010 8:30:10 PM

I should also add that the behavior of MFC if an exception is thrown from inside
Serialize() is not documented, and therefore, it does whatever it does.  The next release
might do something completely different!
				joe

On Mon, 21 Jun 2010 15:21:51 -0400, "RB" <NoMail@NoSpam> wrote:

>
>
>> You should avoid these obsolete macros.  They were created before the 
>> C++ compiler correctly implemented (or implemented at all) the C++ 
>> exception syntax.
>> ****
>> Use try (lower case)
>>>      {
>>>        ar >> FileID;                 
>>>        if (FileID != 0x1234ABCD)
>> ****
>
>Ok, noted, you gave me so much to work with I will have to get
>back with you on most of this Actually what I am most concerned 
>with right now is learning all of what you just gave me. 
>   I stepped thru my doc return code again and it appears that is not
>currently doing what I had hoped. I realize if I click SAVE it is going to 
>save whatever new document data in currently in the members. What I 
>was hoping for was that the exception code would void out the current 
>lpszFileName doc variable so that at least when I click save it would 
>prompt me for a filename instead of just overwriting what is in the 
>lpszFileName.
>
>> Why is this a hardwired literal?  Why did you not do
>> const DWORD CURRENT_FILEID = 0x1234ABCD;
>> ?
>> ****
>
>Ugh maybe because I am a dummy and have not learned any better?
>
>>>          { // FileID mismatch                         
>>>            AfxThrowUserException( );
>> ****
>> I would have done
>> throw new CWrongFileIDException(FileID)
>> where I would have defined a specific exception that did exactly what 
>> I wanted 
>> class CWrongFileIDException : public CException {
>> public:
>>          DWORD GetFileID() { return fid; }
>>          CWrongFileIDException(DWORD fileid) { fid = fileid; }
>>    protected:
>>          DWORD fid;
>> };
>> 
>> You should not "hijack" some other exception to mean other than what 
>> precisely happened!
>> ****
>
>Ok give me some time to work with this.
>
>> ****
>> Query: why are you putting an English language message in SOURCE code?  
>> That's what STRINGTABLEs are for!
>
>This was only just for "me" to see if / when it was actually called.
> 
>> Query: Why did you declare the variable E so far from where it is used?  
>> It should be written, if you want to keep the really bad idea of English strings, 
>>      CString E = _T("...");
>> that is, you should never declare a variable in a scope wider than it needs to exist!
>
>The stuff about where to declare the vars I really just have not gotten that far yet, 
>but appreciate it and will try to incorporate it into my current attempt to learn 
>exceptions. 
>
>> And for that matter, why did you have to declare a CString for AfxMessageBox? 
>
>Well for the one I did not have to, but I got into the CString originally in order
>to copy the strings together
>
> e->GetErrorMessage(szErrMsg, 255);
>        E = _T("RB from inside AND_CATCH\n");
>        E += szErrMsg;
>// Again the English is just for me to "see" when it was called.
>
>> .....
>> You should also do
>> e->Delete();
>> to handle the case where the exception was thrown with 'new'
>> ****
>
>Ok I will have to digest these new items and look in some other docs for this.
>Thanks.
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/21/2010 8:33:53 PM

Still working on digesting and attempting to implement all you gave me, but
have a couple of quick acknowledgements and questions:

> ****
> If you want your exception code to clear this variable, you will have to do that
> explicitly.  Note that if this value is set AFTER the serialization call, because you are
> handling the excepiton internally and not throwing it, there is zero hope that you will be
> able to deal with this.  Instead, you will have to add a handler for operations like
> File::Save, you will have to put an exception handler in that code, you will have to have
> your very own generic exception class (not CUserException), something like
> CMySerializeException, of which CWrongFilieIDException is but one of the many 
> possible derived classes, and you will have to do a throw; instead of  e->Delete()
> so your exception is seen outside the serialize handler.

Oh ok, well that makes sense. 

> Never be afraid to create your own classes of exceptions when needed.  Never 
> "hijack" some generic class.  Make sure that every exception has useful information in 
> it so you can make a report (I included file name, line #, and offset-into-line in 
> CSyntaxException, and for things like CWrongSymbolException I had a placeholder 
> for the entity I expected, so I would do throw new CWrongSymbolException(file, line, 
> offset, IDS_EXPECTED_VARIABLE_NAME);

Oh, well I am beginning to see more of the concept which I totally misunderstood from
the docs I was reading. So I can derive exception classes not necessarily use ones already
written. I did find docs on the try and throw.

Ugh, do I declare this in global space or in each class it's needed ?

class CWrongFileIDException : public CException {
    public:
          DWORD GetFileID() { return fid; }
          CWrongFileIDException(DWORD fileid) { fid = fileid; }
    protected:
          DWORD fid;
};
///That's all for now. Thanks  !
0
Reply RB 6/21/2010 10:33:54 PM

See below....
On Mon, 21 Jun 2010 18:33:54 -0400, "RB" <NoMail@NoSpam> wrote:

>Still working on digesting and attempting to implement all you gave me, but
>have a couple of quick acknowledgements and questions:
>
>> ****
>> If you want your exception code to clear this variable, you will have to do that
>> explicitly.  Note that if this value is set AFTER the serialization call, because you are
>> handling the excepiton internally and not throwing it, there is zero hope that you will be
>> able to deal with this.  Instead, you will have to add a handler for operations like
>> File::Save, you will have to put an exception handler in that code, you will have to have
>> your very own generic exception class (not CUserException), something like
>> CMySerializeException, of which CWrongFilieIDException is but one of the many 
>> possible derived classes, and you will have to do a throw; instead of  e->Delete()
>> so your exception is seen outside the serialize handler.
>
>Oh ok, well that makes sense. 
>
>> Never be afraid to create your own classes of exceptions when needed.  Never 
>> "hijack" some generic class.  Make sure that every exception has useful information in 
>> it so you can make a report (I included file name, line #, and offset-into-line in 
>> CSyntaxException, and for things like CWrongSymbolException I had a placeholder 
>> for the entity I expected, so I would do throw new CWrongSymbolException(file, line, 
>> offset, IDS_EXPECTED_VARIABLE_NAME);
>
>Oh, well I am beginning to see more of the concept which I totally misunderstood from
>the docs I was reading. So I can derive exception classes not necessarily use ones already
>written. I did find docs on the try and throw.
>
>Ugh, do I declare this in global space or in each class it's needed ?
>
>class CWrongFileIDException : public CException {
>    public:
>          DWORD GetFileID() { return fid; }
>          CWrongFileIDException(DWORD fileid) { fid = fileid; }
>    protected:
>          DWORD fid;
>};
>///That's all for now. Thanks  !
****
It needs to be declared in a context which is known to both the throw and the catch
clauses.  Typically, I will put this in a header file, e.g., MySerialExceptions.h, and
#include it in all the modules that need it.
			joe
****
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/22/2010 12:40:26 AM

On Jun 21, 6:13=A0pm, "RB" <NoMail@NoSpam> wrote:
> In my below foobar first attempt to try exception handling I don't unders=
tand
> the following aspects: =A0(my code at bottom after these framework pastes=
)
>
> 1. I must not be doing something correct because even though both
> my CATCH and AND_CATCH call stuff on return that appears to be
> deleting the exception and taking care of various cleanup.

I would also recommend that you forget TRY, CATCH and the rest of MFC
macros. They are a sad leftover from the time MS C++ compiler didn't
implement exceptions (but MFC people wanted to have them).

MFC has that nasty design flaw with exception handling that it uses
exception __pointers__ (I guess also due to said lack of exceptions in
compiler in early days). This is not normal in C++ code, and a
horrific error. Consequence of these pointers is that design of
ownership of said pointers is complicated (well, not much, but still):
when you catch an MFC exception, and you don't want to re-throw it,
you must call Delete() on it (__NOT__ e.g. delete pException;)

I use C++ try/catch and a macro DEL_ON_EXIT, that I put on top of
every catch where I want to handle the exception, e.g. like so:

try
{
workworkwork();
}
catch(CException* p)
{
  DEL_ON_EXIT(p);
  p->ReportError();
}

DEL_ON_EXIT calls p->Delete() on block exit.

Warning: I'll tear apart code below, it's not good at all. ;-)


> void CFileHandlingDoc::Serialize(CArchive& ar)
> {
> =A0if (ar.IsStoring()) =A0 =A0 =A0
> =A0 =A0{
> =A0 =A0 =A0 ar << FileID; =A0 =A0// DWORD
> =A0 =A0 =A0ar << VerData.Ver << VerData.CpyRt << VerData.Corp; =A0
> =A0 =A0 =A0ar.SerializeClass(RUNTIME_CLASS(CMapStringToString));
> =A0 =A0 =A0ExpMap1.Serialize(ar); =A0 =A0
> =A0 =A0} =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0
> =A0else =A0 =A0 =A0 =A0 =A0 =A0 =A0
> =A0 =A0{
> =A0 =A0 =A0CString E;
> =A0 =A0 =A0TCHAR szErrMsg[255];
> =A0 =A0 =A0TRY
> =A0 =A0 =A0 {
> =A0 =A0 =A0 =A0 ar >> FileID; =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0
> =A0 =A0 =A0 =A0 if (FileID !=3D 0x1234ABCD)
> =A0 =A0 =A0 =A0 =A0 { // FileID mismatch =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0
> =A0 =A0 =A0 =A0 =A0 =A0 AfxThrowUserException( );

This is bad. CUserException is a special exception type. You use it
like so: first, you inform the user what went wrong, then you throw it
and leave it to MFC to "handle". MFC actually ignores it, assuming
that user was already informed about what went wrong.

So in this case, you first inform the user what went wrongm then
throw. What happens in this particular case is that it goes to
document's ReportSaveLoadException and gets ignored there.

So... Given how CUserException is specified, inform the user about
what went before throwing. That's rule 0 of CUserException. Rule 1 is:
avoid using it. Given that you need to inform the user what's
happening, it's better to throw an exception that contains whatever
info about the error you want (including message to the user) catch it
and report it higher up the stack (most likely, that means letting it
be handled by MFC somewhere). There's a catch WRT
ReportSaveLoadException and that idea, though, so for now, just inform
the user and throw "user" exception.

> =A0 =A0 =A0 =A0 =A0 }
> =A0 =A0 =A0 =A0 ar >> VerData.Ver >> VerData.CpyRt >> VerData.Corp;
> =A0 =A0 =A0 =A0 ar.SerializeClass(RUNTIME_CLASS(CMapStringToString)); // =
WriteClass CmStS's data
> =A0 =A0 =A0 =A0 ExpMap1.Serialize(ar); =A0 =A0// CMapStringToString's key=
s and values
>
> =A0 =A0 =A0 }

This is bad, and it shows massive confusion WRT exceptions. In 99% of
cases, if you throw and catch same exception type in one function,
you're doing it wrong.

In fact, a piece of advice for a beginner: in 99% of cases, if you
think that you need to write a try/catch, you're doing it wrong. What
you should do instead is ask yourself "if I throw here, where is
exception caught?" Find the answer to that, and you'll find that you
don't need a try/catch. (Exception to that rule: various "creation"
functions of MFC that you can override, e.g. PreCreateWindow,
OnCreate, OnInitDialog, stuff like that especially e.g. OnCreate
should not allow that exception escapes from them.

> =A0 =A0 =A0CATCH( CUserException, e )
> =A0 =A0 =A0 {
> =A0 =A0 =A0 =A0 E =3D _T("BAD FileID, RB from inside CATCH\n");
> =A0 =A0 =A0 =A0 AfxMessageBox( E );
> =A0 =A0 =A0 =A0 return;
> =A0 =A0 =A0 }
> =A0 =A0 =A0AND_CATCH( CException, e )
> =A0 =A0 =A0 {
> =A0 =A0 =A0 =A0 // For other exception types, notify user here.
> =A0 =A0 =A0 =A0 e->GetErrorMessage(szErrMsg, 255);
> =A0 =A0 =A0 =A0 E =3D _T("RB from inside AND_CATCH\n");
> =A0 =A0 =A0 =A0 E +=3D szErrMsg;
> =A0 =A0 =A0 =A0 AfxMessageBox( E );
> =A0 =A0 =A0 =A0 return; =A0
> =A0 =A0 =A0 }
> =A0 =A0 =A0END_CATCH
> =A0 =A0 =A0 =A0 // No exception thrown.
> =A0 =A0}
>
> } =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0

In your case, there should not be ANY try/catch statements in the
whole of Serialize. What you should do, instead, is let exceptions go
through. They will end up in ReportSaveLoadException and be handled
there by MFC.

Goran.

P.S. Don't forget: you are not allowed to write try/catch
statements ;-). If you do, you have 99% chance that you're doing it
wrong. Good C++ code of today has RIDICULOUSLY small number of try/
catch-es in ti.
0
Reply Goran 6/22/2010 8:10:21 AM

On Jun 21, 10:33=A0pm, Joseph M. Newcomer <newco...@flounder.com> wrote:
> I should also add that the behavior of MFC if an exception is thrown from=
 inside
> Serialize() is not documented, and therefore, it does whatever it does. =
=A0The next release
> might do something completely different!

Whoa, not true! It's documented in help for
CDocument::ReportSaveLoadException.

CDocument::ReportSaveLoadException is not perfect (it actually only
handles CFile/Archive exceptions, and for the rest it pops (poops,
rather) up silly "generic" text ("Failed to open document" I think),
so an override of that function might be deemed necessary.

It's not undocumented.

Goran.
0
Reply Goran 6/22/2010 8:15:42 AM

> This is bad. CUserException is a special exception type. 
>..........
>........, 
> it's better to throw an exception that contains whatever info 
> about the error you want (including message to the user) catch it
> and report it higher up the stack (most likely, that means letting it
> be handled by MFC somewhere). There's a catch WRT
> ReportSaveLoadException and that idea, though, so for now, 
> just inform the user and throw "user" exception.

Ok, ( Joe previously told me I had missed the concept by 
trying to use another Exception for my specific scenario) so
I am understanding that. And even though I not really ready
to ask any new questions currently, I did want to respond
and let you guys know that you have me on the right track, and
I am working on cleaning up my methods while I also learn loads
about what is going on and what I need to do in my handler.
  I've learned so far (from the Debugger) that I don't seem
to need to catch any exceptions other than my own.  IOW
MFC is going to catch a slew of them on it's on and if I 
interfere with a catch on my end, then I had better know 
how to forward the throw back into the mfc handler or I
am going to lose all of the highly important code thereof.
Namely like this   Note all my comments are // RB xxxx

BOOL CDocument::OnOpenDocument(LPCTSTR lpszPathName)
{
    .......
    .......
   CATCH_ALL(e)
      {
        ReleaseFile(pFile, TRUE);
        DeleteContents();   // remove failed contents
   TRY
      {
        // RB this (as you already said ) takes me to code
        // that sorts the exception and reports a msg to
        // user.
        ReportSaveLoadException(lpszPathName, e,
        FALSE, AFX_IDP_FAILED_TO_OPEN_DOC);
    ........
// RB, then after returning back CArchive code
// shuts down the archive and returns back to

CDocument* CSingleDocTemplate::OpenDocumentFile(
             LPCTSTR lpszPathName, BOOL bMakeVisible)
  {
    ......
    ......
    // RB, and comes to this "all important" code which will set the
    // current document (on return to user ) to "untitled" so that
    // an inadvertant save does not overwrite any other filename.
    // I would not get this if I interrupted this exception with my
   // catch and did not forward it along

    if (!pDocument->OnOpenDocument(lpszPathName))
     {
       // user has been alerted to what failed in OnOpenDocument
       TRACE0("CDocument::OnOpenDocument returned FALSE.\n");
        if (bCreated)
          {
             pFrame->DestroyWindow();    // will destroy document
          }
        else if (!pDocument->IsModified())
          {
       // original document is untouched
        pDocument->SetModifiedFlag(bWasModified);
          }
        else
         {
           // we corrupted the original document
           SetDefaultTitle(pDocument);
// RB the above is what I was looking for and and now I have 
// figure out how to call this and any other needed code from any 
// scenario exception throw of my own that does not finish opening 
// the document.
............
............  
// RB or otherwise I am going to get this, which
// is not good and will effect and inadverntant
// overwrite
  pDocument->SetPathName(lpszPathName);
.............
 return pDocument;
}

0
Reply RB 6/22/2010 1:45:51 PM

On Jun 22, 3:45=A0pm, "RB" <NoMail@NoSpam> wrote:

(First off, I rather poorly worded the "user" exception part,
hopefully you understood (seems so).)

> =A0 I've learned so far (from the Debugger) that I don't seem
> to need to catch any exceptions other than my own.

Not even that. Why do you think that? (That is, show an example, let's
discuss it).

More seriously, go back to my advice: when you think that you should
catch, first find where it's going to end if you __don't__ catch it.
Doing that is an eye opener, it really is.

For example, if you are in the middle of a message loop in your
program (e.g. you are handling some message, menu command, dialog
control notification...), you should almost never catch __anything__.
Just let exception fly. It ends up in ProcessWndProcException and gets
reported (using ReportError()). So as long as you made your exceptions
"reportable" (Joe speaks about that, kinda-sorta), you are golden. Of
course, you have to clean up any resources, or internal state,
properly (that is, you need to make your code exception-safe), but
that's another story.

What Joe says about exceptions in general is also right on the money
(the "Never be afraid to create your own classes of exceptions when
needed..." paragraph). __THAT'S__ how things are done well.

Another related observation, you'll find that on the internet if you
look, too... Normally, your exception classes hierarchy will typically
be wide, but +/- shallow (and indeed, that's what happens to Joe in
his "syntax" story).

Goran.
0
Reply Goran 6/22/2010 2:18:43 PM

Hi Goran,
  Got a little bit of logic only stuff here for you that I tried on my work 
break, but I won't be able to fully clean up my code till I get home tonight.

> (First off, I rather poorly worded the "user" exception part,
> hopefully you understood (seems so).)

Ugh well, somethings I understood, others I am still tearing
down my ignorance piece by piece

>> I've learned so far (from the Debugger) that I don't seem
>> to need to catch any exceptions other than my own.

> Not even that. Why do you think that? (That is, show an example, 
> let's discuss it).

Ugh, well if I don't code any exception handlers at all in my code,
and I step thru the serial read (on a file I have made sure is corrupt), 
it takes me to and end of file handler which does all of what I previously 
said. So I would think that at least the reading past end of file looking for 
stuff  ( resulting from grabbing "prewritten length" bytes where they are 
supposed to be, but were not ) would be covered without me coding any 
exception handler.
 Your question makes me feel I still have not conceptualized this
area enough yet.
   Additionally I have this logic going so far.
// in the read loop of MyDoc class serialize
 else               
   { 
     try
      {       
        ar >> FID_Read;;      //  DWORD FID_Read;           
        if (FID_Read != FileID)  // const DWORD FileID;
          { // FileID mismatch 
            throw new CWrongFileIDException();  
          }
        ar >> VerData.Ver >> VerData.CpyRt >> VerData.Corp;
        ar.SerializeClass(RUNTIME_CLASS(CMapStringToString)); 
        ExpMap1.Serialize(ar);            
      }
     catch(CWrongFileIDException* e)     
      {
        // Do whatever I may need here
        // so far nothing that I can tell, in fact it seems I could have just
       // eliminated my try and catch handlers and just called the
      //  AfxThrowArchiveException in the if loop above ?
        e->Delete( );
        AfxThrowArchiveException(CArchiveException::badIndex, NULL ); //Invalid file format
// The above takes me to the exact same cleanup code that I get when
// I read in a corrupt file (with NO exception code at all ) and mfc handlers it.
// And leaves me with an untitled filename eliminating the change if inadvertant
// save overwrite.
      }
   }

0
Reply RB 6/22/2010 3:17:33 PM

See below...
On Tue, 22 Jun 2010 01:15:42 -0700 (PDT), Goran <goran.pusic@gmail.com> wrote:

>On Jun 21, 10:33�pm, Joseph M. Newcomer <newco...@flounder.com> wrote:
>> I should also add that the behavior of MFC if an exception is thrown from inside
>> Serialize() is not documented, and therefore, it does whatever it does. �The next release
>> might do something completely different!
>
>Whoa, not true! It's documented in help for
>CDocument::ReportSaveLoadException.
>
>CDocument::ReportSaveLoadException is not perfect (it actually only
>handles CFile/Archive exceptions, and for the rest it pops (poops,
>rather) up silly "generic" text ("Failed to open document" I think),
>so an override of that function might be deemed necessary.
****
OK, I had not looked there.  I only looked at CObject::Serialize, which SHOULD have had a
cross-reference to CDocument::ReportSaveLoadException, and didn't.  
				joe
**** 
>
>It's not undocumented.
>
>Goran.
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/22/2010 5:03:55 PM

See below...
On Tue, 22 Jun 2010 01:10:21 -0700 (PDT), Goran <goran.pusic@gmail.com> wrote:

>On Jun 21, 6:13�pm, "RB" <NoMail@NoSpam> wrote:
>> In my below foobar first attempt to try exception handling I don't understand
>> the following aspects: �(my code at bottom after these framework pastes)
>>
>> 1. I must not be doing something correct because even though both
>> my CATCH and AND_CATCH call stuff on return that appears to be
>> deleting the exception and taking care of various cleanup.
>
>I would also recommend that you forget TRY, CATCH and the rest of MFC
>macros. They are a sad leftover from the time MS C++ compiler didn't
>implement exceptions (but MFC people wanted to have them).
>
>MFC has that nasty design flaw with exception handling that it uses
>exception __pointers__ (I guess also due to said lack of exceptions in
>compiler in early days). This is not normal in C++ code, and a
>horrific error. Consequence of these pointers is that design of
>ownership of said pointers is complicated (well, not much, but still):
>when you catch an MFC exception, and you don't want to re-throw it,
>you must call Delete() on it (__NOT__ e.g. delete pException;)
****
Note that the Delete() method has the additional (mis)feature that if it throws a pointer
to a statically-allocated object that the Delete() is smart enough to not try to delete
it; however, the delete operator will usually result in an assertion failure in the
allocator.

Yes, the whole MFC mechanism had to be backward-compatible with the old macros, which I
believe once did setjmp/longjmp and therefore needed pointers, so when real C++ exceptions
were added, they had to fit them into a world where pointers were used.  Unfortunately,
none of the documentation is correct and does not explicitly state that pointers are being
used.
****
>
>I use C++ try/catch and a macro DEL_ON_EXIT, that I put on top of
>every catch where I want to handle the exception, e.g. like so:
>
>try
>{
>workworkwork();
>}
>catch(CException* p)
>{
>  DEL_ON_EXIT(p);
>  p->ReportError();
>}
>
>DEL_ON_EXIT calls p->Delete() on block exit.
>
>Warning: I'll tear apart code below, it's not good at all. ;-)
>
>
>> void CFileHandlingDoc::Serialize(CArchive& ar)
>> {
>> �if (ar.IsStoring()) � � �
>> � �{
>> � � � ar << FileID; � �// DWORD
>> � � �ar << VerData.Ver << VerData.CpyRt << VerData.Corp; �
>> � � �ar.SerializeClass(RUNTIME_CLASS(CMapStringToString));
>> � � �ExpMap1.Serialize(ar); � �
>> � �} � � � � � � � � � � � � � � � � � � � �
>> �else � � � � � � �
>> � �{
>> � � �CString E;
>> � � �TCHAR szErrMsg[255];
>> � � �TRY
>> � � � {
>> � � � � ar >> FileID; � � � � � � � �
>> � � � � if (FileID != 0x1234ABCD)
>> � � � � � { // FileID mismatch � � � � � � � � � � � �
>> � � � � � � AfxThrowUserException( );
>
>This is bad. CUserException is a special exception type. You use it
>like so: first, you inform the user what went wrong, then you throw it
>and leave it to MFC to "handle". MFC actually ignores it, assuming
>that user was already informed about what went wrong.
>
>So in this case, you first inform the user what went wrongm then
>throw. What happens in this particular case is that it goes to
>document's ReportSaveLoadException and gets ignored there.
>
>So... Given how CUserException is specified, inform the user about
>what went before throwing. That's rule 0 of CUserException. Rule 1 is:
>avoid using it. Given that you need to inform the user what's
>happening, it's better to throw an exception that contains whatever
>info about the error you want (including message to the user) catch it
>and report it higher up the stack (most likely, that means letting it
>be handled by MFC somewhere). There's a catch WRT
>ReportSaveLoadException and that idea, though, so for now, just inform
>the user and throw "user" exception.
>
>> � � � � � }
>> � � � � ar >> VerData.Ver >> VerData.CpyRt >> VerData.Corp;
>> � � � � ar.SerializeClass(RUNTIME_CLASS(CMapStringToString)); // WriteClass CmStS's data
>> � � � � ExpMap1.Serialize(ar); � �// CMapStringToString's keys and values
>>
>> � � � }
>
>This is bad, and it shows massive confusion WRT exceptions. In 99% of
>cases, if you throw and catch same exception type in one function,
>you're doing it wrong.
>
>In fact, a piece of advice for a beginner: in 99% of cases, if you
>think that you need to write a try/catch, you're doing it wrong. What
>you should do instead is ask yourself "if I throw here, where is
>exception caught?" Find the answer to that, and you'll find that you
>don't need a try/catch. (Exception to that rule: various "creation"
>functions of MFC that you can override, e.g. PreCreateWindow,
>OnCreate, OnInitDialog, stuff like that especially e.g. OnCreate
>should not allow that exception escapes from them.
>
>> � � �CATCH( CUserException, e )
>> � � � {
>> � � � � E = _T("BAD FileID, RB from inside CATCH\n");
>> � � � � AfxMessageBox( E );
>> � � � � return;
>> � � � }
>> � � �AND_CATCH( CException, e )
>> � � � {
>> � � � � // For other exception types, notify user here.
>> � � � � e->GetErrorMessage(szErrMsg, 255);
>> � � � � E = _T("RB from inside AND_CATCH\n");
>> � � � � E += szErrMsg;
>> � � � � AfxMessageBox( E );
>> � � � � return; �
>> � � � }
>> � � �END_CATCH
>> � � � � // No exception thrown.
>> � �}
>>
>> } � � � � � � � � � �
>
>In your case, there should not be ANY try/catch statements in the
>whole of Serialize. What you should do, instead, is let exceptions go
>through. They will end up in ReportSaveLoadException and be handled
>there by MFC.
>
>Goran.
>
>P.S. Don't forget: you are not allowed to write try/catch
>statements ;-). If you do, you have 99% chance that you're doing it
>wrong. Good C++ code of today has RIDICULOUSLY small number of try/
>catch-es in ti.
****
I'm not sure this is a good piece of advice.  I use try/catch a lot; it is essentially a
"non-local GOTO", a structured way of aborting execution and returning to a known place,
while still guaranteeing that all intermediate destructors for stack variables are called.
It is particularly useful in writing tasks like recursive-descent parsers (particularly if
you just want to stop without trying to do error recovery, which is always hard) and
terminating threads while still guaranteeing that you return from the top-level thread
function.  It is  clean and well-structured way of aborting a partially-completed
operation.  An it is the only way to report errors from operations like 'new'.  Also, look
at the number of exceptions that can be thrown by std:: or boost::.
				joe

Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/22/2010 5:12:33 PM

See below....
On Tue, 22 Jun 2010 09:45:51 -0400, "RB" <NoMail@NoSpam> wrote:

>
>> This is bad. CUserException is a special exception type. 
>>..........
>>........, 
>> it's better to throw an exception that contains whatever info 
>> about the error you want (including message to the user) catch it
>> and report it higher up the stack (most likely, that means letting it
>> be handled by MFC somewhere). There's a catch WRT
>> ReportSaveLoadException and that idea, though, so for now, 
>> just inform the user and throw "user" exception.
>
>Ok, ( Joe previously told me I had missed the concept by 
>trying to use another Exception for my specific scenario) so
>I am understanding that. And even though I not really ready
>to ask any new questions currently, I did want to respond
>and let you guys know that you have me on the right track, and
>I am working on cleaning up my methods while I also learn loads
>about what is going on and what I need to do in my handler.
>  I've learned so far (from the Debugger) that I don't seem
>to need to catch any exceptions other than my own.  IOW
>MFC is going to catch a slew of them on it's on and if I 
>interfere with a catch on my end, then I had better know 
>how to forward the throw back into the mfc handler or I
>am going to lose all of the highly important code thereof.
****
But MFC doesn't always handle them "gracefully".  For example, in the inner loop of the
MFC command dispatcher, if it gets an excpeption it pops up a completely useless
MessageBox which helps neither the end user nor tech support in the slightest.  
****
>Namely like this   Note all my comments are // RB xxxx
>
>BOOL CDocument::OnOpenDocument(LPCTSTR lpszPathName)
>{
>    .......
>    .......
>   CATCH_ALL(e)
>      {
>        ReleaseFile(pFile, TRUE);
>        DeleteContents();   // remove failed contents
>   TRY
>      {
>        // RB this (as you already said ) takes me to code
>        // that sorts the exception and reports a msg to
>        // user.
>        ReportSaveLoadException(lpszPathName, e,
>        FALSE, AFX_IDP_FAILED_TO_OPEN_DOC);
>    ........
>// RB, then after returning back CArchive code
>// shuts down the archive and returns back to
>
>CDocument* CSingleDocTemplate::OpenDocumentFile(
>             LPCTSTR lpszPathName, BOOL bMakeVisible)
>  {
>    ......
>    ......
>    // RB, and comes to this "all important" code which will set the
>    // current document (on return to user ) to "untitled" so that
>    // an inadvertant save does not overwrite any other filename.
>    // I would not get this if I interrupted this exception with my
>   // catch and did not forward it along
>
>    if (!pDocument->OnOpenDocument(lpszPathName))
>     {
>       // user has been alerted to what failed in OnOpenDocument
>       TRACE0("CDocument::OnOpenDocument returned FALSE.\n");
>        if (bCreated)
>          {
>             pFrame->DestroyWindow();    // will destroy document
>          }
>        else if (!pDocument->IsModified())
>          {
>       // original document is untouched
>        pDocument->SetModifiedFlag(bWasModified);
>          }
>        else
>         {
>           // we corrupted the original document
>           SetDefaultTitle(pDocument);
>// RB the above is what I was looking for and and now I have 
>// figure out how to call this and any other needed code from any 
>// scenario exception throw of my own that does not finish opening 
>// the document.
>...........
>...........  
>// RB or otherwise I am going to get this, which
>// is not good and will effect and inadverntant
>// overwrite
>  pDocument->SetPathName(lpszPathName);
>............
> return pDocument;
>}
***
But the point here is that it *has* called the virtual method ReportSaveLoadException. and
it return FALSE from OnOpenDocument.  For some reason, you omitted that critical code from
this post, although it is present in the actual CDocument::OnOpenDocument method source
code!  

Because this is a virtual method, you could override it and if calling the parent returned
NULL, you could do something useful such as setting the filename to empty.  I think this
code actually is incorrect, but you can create your own subclass and do whatever you want.
				joe
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/22/2010 5:29:38 PM

On Tue, 22 Jun 2010 13:12:33 -0400, Joseph M. Newcomer
<newcomer@flounder.com> wrote:

>>P.S. Don't forget: you are not allowed to write try/catch
>>statements ;-). If you do, you have 99% chance that you're doing it
>>wrong. Good C++ code of today has RIDICULOUSLY small number of try/
>>catch-es in ti.
>****
>I'm not sure this is a good piece of advice.  I use try/catch a lot; it is essentially a
>"non-local GOTO", a structured way of aborting execution and returning to a known place,
>while still guaranteeing that all intermediate destructors for stack variables are called.
>It is particularly useful in writing tasks like recursive-descent parsers (particularly if
>you just want to stop without trying to do error recovery, which is always hard) and
>terminating threads while still guaranteeing that you return from the top-level thread
>function.  It is  clean and well-structured way of aborting a partially-completed
>operation.  An it is the only way to report errors from operations like 'new'.  Also, look
>at the number of exceptions that can be thrown by std:: or boost::.

Goran was not saying exceptions are bad, just that overly frequent use of
try/catch is bad, which it usually is. I've been saying for a long long
time that there's an inverse relationship between the number of try/catch
clauses you have and the effectiveness with which you're using exceptions.
There are a number of reasons for this. On the API designer side, using
exceptions where return codes are more appropriate forces callers to write
try/catch whenever they use the function, so that's a bad use of
exceptions. You never want to turn exception usage into a clumsier version
of return codes. On the user side, try/catch gets overused when people
don't employ the RAII idiom and need to perform clean-up that should be
handled by a destructor. Ideally, exceptions are caught far away from where
they're thrown, in a top-level handler, which reports the error to the
user, logs it, or whatever. It is relatively rare for well-designed code to
need to handle the exception closer to the throw-point.

-- 
Doug Harrison
Visual C++ MVP
0
Reply Doug 6/22/2010 7:14:11 PM

"Doug Harrison [MVP]" <dsh@mvps.org> wrote in message 
news:9c1226ldk8g207f4asif27nehrcfji6g0e@4ax.com...
> On Tue, 22 Jun 2010 13:12:33 -0400, Joseph M. Newcomer
> <newcomer@flounder.com> wrote:
>
>>I'm not sure this is a good piece of advice.  I use try/catch a lot; it is 
>>essentially a
>>"non-local GOTO", a structured way of aborting execution and returning to 
>>a known place,
>>while still guaranteeing that all intermediate destructors for stack 
>>variables are called.
>>It is particularly useful in writing tasks like recursive-descent parsers 
>>(particularly if
>>you just want to stop without trying to do error recovery, which is always 
>>hard) and
>>terminating threads while still guaranteeing that you return from the 
>>top-level thread
>>function.  It is  clean and well-structured way of aborting a 
>>partially-completed
>>operation.  An it is the only way to report errors from operations like 
>>'new'.  Also, look
>>at the number of exceptions that can be thrown by std:: or boost::.
>
> Goran was not saying exceptions are bad, just that overly frequent use of
> try/catch is bad, which it usually is. I've been saying for a long long
> time that there's an inverse relationship between the number of try/catch
> clauses you have and the effectiveness with which you're using exceptions.
> There are a number of reasons for this. On the API designer side, using
> exceptions where return codes are more appropriate forces callers to write
> try/catch whenever they use the function, so that's a bad use of
> exceptions. You never want to turn exception usage into a clumsier version
> of return codes. On the user side, try/catch gets overused when people
> don't employ the RAII idiom and need to perform clean-up that should be
> handled by a destructor. Ideally, exceptions are caught far away from 
> where
> they're thrown, in a top-level handler, which reports the error to the
> user, logs it, or whatever. It is relatively rare for well-designed code 
> to
> need to handle the exception closer to the throw-point.
>

Not to mention, the overhead of throwing exceptions reduces performance if 
many exceptions are thrown.  Exceptions are not meant as a "non-local GOTO". 
Exceptions are meant for rarely occurring ERROR conditions (you know, 
'exceptional' conditions!), not normal control flow.  I once saw a switch 
statement rewritten as a bunch of thrown exceptions, not a pretty sight.

-- David
 

0
Reply David 6/22/2010 9:06:56 PM

See below...
On Tue, 22 Jun 2010 14:14:11 -0500, "Doug Harrison [MVP]" <dsh@mvps.org> wrote:

>On Tue, 22 Jun 2010 13:12:33 -0400, Joseph M. Newcomer
><newcomer@flounder.com> wrote:
>
>>>P.S. Don't forget: you are not allowed to write try/catch
>>>statements ;-). If you do, you have 99% chance that you're doing it
>>>wrong. Good C++ code of today has RIDICULOUSLY small number of try/
>>>catch-es in ti.
>>****
>>I'm not sure this is a good piece of advice.  I use try/catch a lot; it is essentially a
>>"non-local GOTO", a structured way of aborting execution and returning to a known place,
>>while still guaranteeing that all intermediate destructors for stack variables are called.
>>It is particularly useful in writing tasks like recursive-descent parsers (particularly if
>>you just want to stop without trying to do error recovery, which is always hard) and
>>terminating threads while still guaranteeing that you return from the top-level thread
>>function.  It is  clean and well-structured way of aborting a partially-completed
>>operation.  An it is the only way to report errors from operations like 'new'.  Also, look
>>at the number of exceptions that can be thrown by std:: or boost::.
>
>Goran was not saying exceptions are bad, just that overly frequent use of
>try/catch is bad, which it usually is. I've been saying for a long long
>time that there's an inverse relationship between the number of try/catch
>clauses you have and the effectiveness with which you're using exceptions.
>There are a number of reasons for this. On the API designer side, using
>exceptions where return codes are more appropriate forces callers to write
>try/catch whenever they use the function, so that's a bad use of
>exceptions. 
****
I once wrote code for an OS that threw an exception when an API failed.  The result was
one try/catch block per API call, and the code was a nightmare.  Building robust code in
that environment was amazingly challenging, and I consider it one of hte worst designs
I've ever had the misfortune to have to interact with.
****
>You never want to turn exception usage into a clumsier version
>of return codes. 
****
Key here is how far up you need to get control.  Return codes are often clumsy in this
regard, and so a lot of it has to do with the need to cleanly return to a very high point
in the call stack.  The complement of have APIs throw exceptions is having the need to
"return FALSE" everywhere, but that turns out to be "return NULL" sometimes and "return 0"
other times, or "return -1" (e.g., when a count is expected).  These have the additional
problem of losing the reason for the failure, so by the time it gets to the necessary
level the only information you have is "something failed down there" and you don't know
what or where, or necessarily even how to recover from it.  Exceptions can provide a rich
set of information on the nature of the failure, and return it intact to abribrary levels
up the call hiearchy, and that is a LOT of power!
****
>On the user side, try/catch gets overused when people
>don't employ the RAII idiom and need to perform clean-up that should be
>handled by a destructor. 
*****
Part of the problem is that not everything is encapsulable in RAII.  For example, if I
should return a pointer to an object, the object must have a lifetime that exceeds scope.
But if there is a failure, I should free the storage up.  RAII doesn't handle this
gracefully.  Other examples include "either I will return a handle or no handle will be
allocated" but you have to allocate the handle to make progress.  RAII is powerful,
partcularly with smart pointers, but it is always based on the premise that leaving scope
means deletion of whatever resources are consumed, and that is not always feasible.
****
>Ideally, exceptions are caught far away from where
>they're thrown, in a top-level handler, which reports the error to the
>user, logs it, or whatever. It is relatively rare for well-designed code to
>need to handle the exception closer to the throw-point.
****
I agree.  If-statements work very well for this.  I only use it to terminate threads
cleanly and abort deep recursions all the way back up to the top level.
			joe
****
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/22/2010 9:27:17 PM

Well I'm glad that my thread is getting a lot of input, but
most of the talk on this section is loosing me at my level.
I'm getting confused as to whether I should "try and catch"
on not "try and catch". If you would, could you please 
comment on my code with question comments below.
It is not that long and you can just say whatever brief
or elongation review you have time for.
---------------
   Additionally I have this logic going so far.
// in the read loop of MyDoc class serialize
 else               
   { 
     try
      {       
        ar >> FID_Read;;      //  DWORD FID_Read;           
        if (FID_Read != FileID)  // const DWORD FileID;
          { // FileID mismatch 
            throw new CWrongFileIDException();  
          }
        ar >> VerData.Ver >> VerData.CpyRt >> VerData.Corp;
        ar.SerializeClass(RUNTIME_CLASS(CMapStringToString)); 
        ExpMap1.Serialize(ar);            
      }
     catch(CWrongFileIDException* e)     
      {
        // Do whatever I may need here
        // so far nothing that I can tell, in fact it seems I could have just
       // eliminated my try and catch handlers and just called the
      //  AfxThrowArchiveException in the if loop above ?
        e->Delete( );
        AfxThrowArchiveException(CArchiveException::badIndex, NULL ); //Invalid file format
// The above takes me to the exact same cleanup code that I get when
// I read in a corrupt file (with NO exception code at all ) and mfc handlers it.
// And leaves me with an untitled filename eliminating the change if inadvertant
// save overwrite.
      }
   }

0
Reply RB 6/22/2010 10:09:39 PM

To maximize performance, the Microsoft implementation was designed to create exception
frames extremely quickly (the try blocks) and it was (I believe rightly) felt that any
costs required to actually handle the exceptions could be paid at the time the exception
was thrown.  I think this is a good engineering tradeoff.  So yes, throwing an exception
is a pretty heavy-duty operation.  But when an error occurs, you are going to be reduced
to working in "people time" (that is, someone is going to have to read the error message
and respond to it, integer seconds if not integer tens of seconds) so expending a few
hundred microseconds (remember, on a 3GHz machine, we can execute as many as 6
instructions per nanosecond (and that's on the OLD Pentium machines, not the Core
architectures which can do more), so a microsecond is a *lot* of instructions.  (For those
of you who don't believe the arithmetic, look up "superscalar architecture").  

So having exceptions as a basic loop control structure is going to be a Really Bad Idea.
But frankly, understanding such "spaghetti" code is extremely difficult, and trust me, the
worst assembler spaghetti code is clear as crystal compared to some of the
exception-driven code I've had to plow through!  Exceptions are just that: something went
wrong.
			joe
On Tue, 22 Jun 2010 14:06:56 -0700, "David Ching" <dc@remove-this.dcsoft.com> wrote:

>
>"Doug Harrison [MVP]" <dsh@mvps.org> wrote in message 
>news:9c1226ldk8g207f4asif27nehrcfji6g0e@4ax.com...
>> On Tue, 22 Jun 2010 13:12:33 -0400, Joseph M. Newcomer
>> <newcomer@flounder.com> wrote:
>>
>>>I'm not sure this is a good piece of advice.  I use try/catch a lot; it is 
>>>essentially a
>>>"non-local GOTO", a structured way of aborting execution and returning to 
>>>a known place,
>>>while still guaranteeing that all intermediate destructors for stack 
>>>variables are called.
>>>It is particularly useful in writing tasks like recursive-descent parsers 
>>>(particularly if
>>>you just want to stop without trying to do error recovery, which is always 
>>>hard) and
>>>terminating threads while still guaranteeing that you return from the 
>>>top-level thread
>>>function.  It is  clean and well-structured way of aborting a 
>>>partially-completed
>>>operation.  An it is the only way to report errors from operations like 
>>>'new'.  Also, look
>>>at the number of exceptions that can be thrown by std:: or boost::.
>>
>> Goran was not saying exceptions are bad, just that overly frequent use of
>> try/catch is bad, which it usually is. I've been saying for a long long
>> time that there's an inverse relationship between the number of try/catch
>> clauses you have and the effectiveness with which you're using exceptions.
>> There are a number of reasons for this. On the API designer side, using
>> exceptions where return codes are more appropriate forces callers to write
>> try/catch whenever they use the function, so that's a bad use of
>> exceptions. You never want to turn exception usage into a clumsier version
>> of return codes. On the user side, try/catch gets overused when people
>> don't employ the RAII idiom and need to perform clean-up that should be
>> handled by a destructor. Ideally, exceptions are caught far away from 
>> where
>> they're thrown, in a top-level handler, which reports the error to the
>> user, logs it, or whatever. It is relatively rare for well-designed code 
>> to
>> need to handle the exception closer to the throw-point.
>>
>
>Not to mention, the overhead of throwing exceptions reduces performance if 
>many exceptions are thrown.  Exceptions are not meant as a "non-local GOTO". 
>Exceptions are meant for rarely occurring ERROR conditions (you know, 
>'exceptional' conditions!), not normal control flow.  I once saw a switch 
>statement rewritten as a bunch of thrown exceptions, not a pretty sight.
>
>-- David
> 
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/22/2010 10:11:43 PM

On 22/06/2010 23:06, David Ching wrote:

> Exceptions are meant for rarely occurring ERROR conditions (you
> know, 'exceptional' conditions!), not normal control flow.I once saw a
> switch statement rewritten as a bunch of thrown exceptions, not a pretty
> sight.

I do agree with you David.

The Parse vs. TryParse case of .NET comes in my mind: the earlier 
versions of the framework had the Parse method, which threw exceptions 
in case of parsing error. In later versions (since 2.0?) they introduced 
TryParse, which just returned an error code.

Surrounding Parse calls with try/catch blocks produced bad code; instead 
a simple if-check of TryParse return code is much better, IMHO.

Giovanni

0
Reply Giovanni 6/22/2010 10:18:49 PM

> ***
> But the point here is that it *has* called the virtual method 
> ReportSaveLoadException. and it return FALSE from OnOpenDocument. 
> ............
> Because this is a virtual method, you could override it and if calling the parent 
> returned NULL, you could do something useful such as setting the filename to 
> empty.  I think this code actually is incorrect, but you can create your own 
> subclass and do whatever you want.
------------------------------------------
Hey Joe, this is getting a bit confusing for me. Why would I want to create my
own subclass to set the filename to empty when the below framwork code 
(that I previously posted ) sets the filename to "untitled" for me which keeps
me from inadvertly saving and overwriting any previous persistence ? ?
>>    if (!pDocument->OnOpenDocument(lpszPathName))
>>     {
>>        ........
>>        else
>>         {
>>           SetDefaultTitle(pDocument);
>>// RB the above sets the filename to "untitled" 
>>...........

0
Reply RB 6/22/2010 10:35:05 PM

On Tue, 22 Jun 2010 17:27:17 -0400, Joseph M. Newcomer
<newcomer@flounder.com> wrote:

>Part of the problem is that not everything is encapsulable in RAII.  For example, if I
>should return a pointer to an object, the object must have a lifetime that exceeds scope.
>But if there is a failure, I should free the storage up.  RAII doesn't handle this
>gracefully.  Other examples include "either I will return a handle or no handle will be
>allocated" but you have to allocate the handle to make progress.  RAII is powerful,
>partcularly with smart pointers, but it is always based on the premise that leaving scope
>means deletion of whatever resources are consumed, and that is not always feasible.

That's really not a problem. Smart pointer classes can have a "release"
function, that returns the encapsulated pointer and relinquishes ownership.
For example, here's a function I wrote to get an IShellFolder interface
(encapsulated in a COM smart pointer) and optionally return a PIDL for an
absolute path:

IShellFolderPtr
GetFolder(
      const wchar_t* path,
      LPITEMIDLIST* pidlFolder = 0,
      HWND hWnd = 0)
{
   IShellFolder* pDesktop = GetDesktop();
   nc_ITEMIDLIST_ptr pidl(GetPidl(pDesktop, path, hWnd));
   IShellFolder* pFolder;
   Co::Vet(pDesktop->BindToObject(
         pidl.get(), 0, IID_IShellFolder, (void**) &pFolder));
   if (pidlFolder)
      *pidlFolder = pidl.release();
   return IShellFolderPtr(pFolder, false);
}

I used the nc_ITEMIDLIST_ptr ("nc" means non-copyable i.e. not
reference-counted and not weirdly copyable like auto_ptr) to protect the
PIDL across the call to Co::Vet, which is my function to turn HRESULT
errors into exceptions. After the IShellFolder pointer is obtained, if
pidlFolder is non-NULL, the pointer is released from pidl and stored to it,
transferring ownership to the caller. If pidlFolder is NULL, the PIDL is
deleted when the function returns and pidl is destroyed. The creation of
the IShellFolderPtr cannot fail, so this is exception-safe. (The GetDesktop
result is a cached value that is allocated on first call, so it doesn't
leak if an exception is thrown.)

Using RAII like this can linearize a function that would otherwise be
cluttered with multiple try/catch blocks or deeply nested ifs or serial ifs
with multiple goto targets at the bottom of the function.

-- 
Doug Harrison
Visual C++ MVP
0
Reply Doug 6/22/2010 10:43:33 PM

"RB" <NoMail@NoSpam> wrote in message 
news:#h3PhelELHA.1272@TK2MSFTNGP05.phx.gbl...
> Well I'm glad that my thread is getting a lot of input, but
> most of the talk on this section is loosing me at my level.
> I'm getting confused as to whether I should "try and catch"
> on not "try and catch". If you would, could you please comment on my code 
> with question comments below.
> It is not that long and you can just say whatever brief
> or elongation review you have time for.
> ---------------
>   Additionally I have this logic going so far.
> // in the read loop of MyDoc class serialize
> else               { try
>      {       ar >> FID_Read;;      //  DWORD FID_Read;           if 
> (FID_Read != FileID)  // const DWORD FileID;
>          { // FileID mismatch throw new CWrongFileIDException();  }
>        ar >> VerData.Ver >> VerData.CpyRt >> VerData.Corp;
>        ar.SerializeClass(RUNTIME_CLASS(CMapStringToString)); 
> ExpMap1.Serialize(ar);            }
>     catch(CWrongFileIDException* e)     {
>        // Do whatever I may need here
>        // so far nothing that I can tell, in fact it seems I could have 
> just
>       // eliminated my try and catch handlers and just called the
>      //  AfxThrowArchiveException in the if loop above ?
>        e->Delete( );
>        AfxThrowArchiveException(CArchiveException::badIndex, NULL ); 
> //Invalid file format
> // The above takes me to the exact same cleanup code that I get when
> // I read in a corrupt file (with NO exception code at all ) and mfc 
> handlers it.
> // And leaves me with an untitled filename eliminating the change if 
> inadvertant
> // save overwrite.
>      }
>   }
>

I agree with your final comment; there is no reason to throw 
CWrongFileIDException when the only thing catching it is right below. 
Optimize like this:

    ar >> FID_Read;;      //  DWORD FID_Read;
    if (FID_Read != FileID)  // const DWORD FileID;
    { // FileID mismatch
        AfxThrowArchiveException(CArchiveException::badIndex, NULL ); 
//Invalid file format
        return;
    }
    ar >> VerData.Ver >> VerData.CpyRt >> VerData.Corp;
    ar.SerializeClass(RUNTIME_CLASS(CMapStringToString));
    ExpMap1.Serialize(ar);


-- David 

0
Reply David 6/22/2010 10:58:56 PM

See below...
On Tue, 22 Jun 2010 18:09:39 -0400, "RB" <NoMail@NoSpam> wrote:

>Well I'm glad that my thread is getting a lot of input, but
>most of the talk on this section is loosing me at my level.
>I'm getting confused as to whether I should "try and catch"
>on not "try and catch". If you would, could you please 
>comment on my code with question comments below.
>It is not that long and you can just say whatever brief
>or elongation review you have time for.
>---------------
>   Additionally I have this logic going so far.
>// in the read loop of MyDoc class serialize
> else               
>   { 
>     try
>      {       
>        ar >> FID_Read;;      //  DWORD FID_Read;           
>        if (FID_Read != FileID)  // const DWORD FileID;
>          { // FileID mismatch 
>            throw new CWrongFileIDException();  
****
As already pointed out, doing a throw directly inside a try is probably not good style.
Now if you called another function that called a function that called a function that did
a throw, that makes more sense.

Key here is how much you have to do in the catch.  Putting all the recovery code in the
catch would consolidate it and eliminate that horror of "goto exit" that happens so often.
But frankly, if you're doing that, the right way to handle it is more likely to put the
code in a function this one calls, and just return FALSE if there is an error.  Then do
what you need to do to clean up in the else branch of the if.
****
>          }
>        ar >> VerData.Ver >> VerData.CpyRt >> VerData.Corp;
>        ar.SerializeClass(RUNTIME_CLASS(CMapStringToString)); 
>        ExpMap1.Serialize(ar);            
>      }
>     catch(CWrongFileIDException* e)     
>      {
>        // Do whatever I may need here
>        // so far nothing that I can tell, in fact it seems I could have just
>       // eliminated my try and catch handlers and just called the
>      //  AfxThrowArchiveException in the if loop above ?
>        e->Delete( );
>        AfxThrowArchiveException(CArchiveException::badIndex, NULL ); //Invalid file format
>// The above takes me to the exact same cleanup code that I get when
>// I read in a corrupt file (with NO exception code at all ) and mfc handlers it.
>// And leaves me with an untitled filename eliminating the change if inadvertant
>// save overwrite.
>      }
>   }
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/22/2010 11:49:02 PM

Note that this could be handled as

BOOL TryParse(...args...)
    {
     try 
        { 
         Parse(...);
         return TRUE;
        }
    catch(..whatever..)
        {
         return FALSE;
        }
}

It ain't rocket science.  And it isn't clear to me how handling the exception results in
"bad code".
					oje

On Wed, 23 Jun 2010 00:18:49 +0200, Giovanni Dicanio
<giovanniDOTdicanio@REMOVEMEgmail.com> wrote:

>On 22/06/2010 23:06, David Ching wrote:
>
>> Exceptions are meant for rarely occurring ERROR conditions (you
>> know, 'exceptional' conditions!), not normal control flow.I once saw a
>> switch statement rewritten as a bunch of thrown exceptions, not a pretty
>> sight.
>
>I do agree with you David.
>
>The Parse vs. TryParse case of .NET comes in my mind: the earlier 
>versions of the framework had the Parse method, which threw exceptions 
>in case of parsing error. In later versions (since 2.0?) they introduced 
>TryParse, which just returned an error code.
>
>Surrounding Parse calls with try/catch blocks produced bad code; instead 
>a simple if-check of TryParse return code is much better, IMHO.
>
>Giovanni
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/22/2010 11:51:34 PM

See below...
On Tue, 22 Jun 2010 18:35:05 -0400, "RB" <NoMail@NoSpam> wrote:

>> ***
>> But the point here is that it *has* called the virtual method 
>> ReportSaveLoadException. and it return FALSE from OnOpenDocument. 
>> ............
>> Because this is a virtual method, you could override it and if calling the parent 
>> returned NULL, you could do something useful such as setting the filename to 
>> empty.  I think this code actually is incorrect, but you can create your own 
>> subclass and do whatever you want.
>------------------------------------------
>Hey Joe, this is getting a bit confusing for me. Why would I want to create my
>own subclass to set the filename to empty when the below framwork code 
>(that I previously posted ) sets the filename to "untitled" for me which keeps
>me from inadvertly saving and overwriting any previous persistence ? ?
>>>    if (!pDocument->OnOpenDocument(lpszPathName))
****
If throwing the exception works, then the answer is, you wouldn't want to do this.  But I
thought you said that it didn't solve the problem.
				joe
****
>>>     {
>>>        ........
>>>        else
>>>         {
>>>           SetDefaultTitle(pDocument);
>>>// RB the above sets the filename to "untitled" 
>>>...........
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/22/2010 11:54:08 PM

> ****
> If throwing the exception works, then the answer is, you wouldn't want to do this.  

Oh ok, thanks.

> But I thought you said that it didn't solve the problem.
> ****

No, I said that when I interrupted the "end of file" exception
by inserting a catch ( CException, e ) 
( which I'm sure was a mistake now) then I lost the mfc cleanup.
But if mfc catches it on it's own without any try / catch on my part
and does all the cleanup and setting the filename to "untitled"
( found all of this out by stepping thru the framework for each
  scenario)
And to the dilemma of my file id I found that if I threw the
AfxThrowArchiveException in my if loop (code below)
that it gave me all the same cleanup and reset code said above.

ar >> FID_Read;;      //  DWORD FID_Read;           
 if (FID_Read != FileID)  // const DWORD FileID;
  { // FileID mismatch 
     AfxThrowArchiveException(CArchiveException::badIndex, NULL ); //Invalid file format 
  }
ar >> VerData.Ver >> VerData.CpyRt >> VerData.Corp;
ar.SerializeClass(RUNTIME_CLASS(CMapStringToString)); 
ExpMap1.Serialize(ar);            
/// Also note I put the file id in a const as you told me.
0
Reply RB 6/23/2010 12:14:08 AM

> ****
> As already pointed out, doing a throw directly inside a try is probably not good style.
> Now if you called another function that called a function that called a function that did
> a throw, that makes more sense.

Oh ok, so like if I ,

// declared in CMyDoc.h
 const DWORD FileID;

// and in my doc ctor 
CMyDoc::CMyDoc( ) : FileID(FILE_ID) 
{ 
   VerData.Ver.Format(  _T("Version %d.%d.%d.%d"), VERMAJ, VERMIN, VERFIX, BUILDNUM );
   VerData.CpyRt = _T(CPY_RT_YR_STR_LITERAL);
}   

// and in my doc serialize do,
   try
     {       
      DWORD FID_Read;           
       ar >> FID_Read;;     
       Check_ID_Match ( FID_Read );
       .........
       ..........
///////////////////////////////////////////////////////////////
void CMyDocClass::Check_ID_Match ( DWORD&  Read )
  {
     if ( Read != FileID)  
      { // FileID mismatch 
         throw new CWhateverDoesTheJob( ByReadingDocsAndOrSteppingThru);
       }
  }

0
Reply RB 6/23/2010 12:36:18 AM

"Joseph M. Newcomer" <newcomer@flounder.com> wrote in message 
news:d0j2261qbnp0hepna91efqiiesg126u0st@4ax.com...
> Note that this could be handled as
>
> BOOL TryParse(...args...)
>    {
>     try
>        {
>         Parse(...);
>         return TRUE;
>        }
>    catch(..whatever..)
>        {
>         return FALSE;
>        }
> }
>
> It ain't rocket science.  And it isn't clear to me how handling the 
> exception results in
> "bad code".
> oje
>

This implementation of TryParse() doesn't solve the problem we were talking 
about.  The problem is that if an exception is thrown for the common 
occurrence of malformed args, the result is it is SLOWNESS!  This 
implementation would fix this problem:

  BOOL TryParse(...args...)
  {
        if (!IsValid(args))
           return FALSE;

           Parse(...);    // Parse() will not throw because args are valid
           return TRUE;
  }


-- David
 

0
Reply David 6/23/2010 2:10:53 AM

Actually in summation of all that has transpired on this thread I 
wanted to clarify my last post. First I realize that if I implement
a try then I would also have a catch which I did not show in
my previous post.  If I needed a try and catch, I feel that you
guys have taught me the basics of that.
    In addition I understand that in many cases one could if
circumstances warrant, throw a framework (or other available)
exception (or call a function that would throw it ) from a code
segment "without" implementing any try and catch.
    I am still a neophite by any means in this area but this 
thread has taught me a bunch. And I thank all of you.
I am still waiting to get Goran's final input also since the tonights
expanded input of this thread in his timezone will catch him asleep.
0
Reply RB 6/23/2010 3:29:10 AM

Again, the question is performance: if you had to open a file, read data in, and finally
invoke the parsing, what percentage of the time is spent handling an exception.

An exact number, expressed in some quantity of nanoseconds, microseconds, or milliseconds
is essential here.  I don't buy "slowness" unless there is a precise quantity specified.

And, the absolute number is not relevant either; the number has to be expressed as a
percentage of the total processing time required, and once "user time" gets into the mix
(a user having to read a MessageBox or something like that) then it becomes a percentage
of tens of seconds.

I spent 15 years worrying about these issues, and by the end of the work, we measured down
to the microsecond (on 1MIPS machines, so we could get resolution down to the single
instruction; the architecture, a mainframe, had the equivalent of the x86 RDTSC
instruction).  One thing I learned, was that anyone who started claiming that "X is a
performance problem" was usually basing it on rumor and hearsay; once we instrumented the
code, we found performance was often down in single-digit microseconds.  And in one case
where it was in hundreds of microseconds, the situation was an error that invalidated a
complete run of the program, so we'd lost minutes; the extra few hundred microseconds
wasn't even worthy of discussion (the time spent formatting the error line to the printer
was about an order of magnitude slower than the exception handling, in a language that
didn't really have exception handling...just the equivalent of setjmp/longjmp, which he
had been told was "slow", as if it mattered).

The bottom line: whenever you ask a programmer "Where is the performance bottleneck in
your code?", you will get the wrong answer.  
					joe
****
On Tue, 22 Jun 2010 19:10:53 -0700, "David Ching" <dc@remove-this.dcsoft.com> wrote:

>"Joseph M. Newcomer" <newcomer@flounder.com> wrote in message 
>news:d0j2261qbnp0hepna91efqiiesg126u0st@4ax.com...
>> Note that this could be handled as
>>
>> BOOL TryParse(...args...)
>>    {
>>     try
>>        {
>>         Parse(...);
>>         return TRUE;
>>        }
>>    catch(..whatever..)
>>        {
>>         return FALSE;
>>        }
>> }
>>
>> It ain't rocket science.  And it isn't clear to me how handling the 
>> exception results in
>> "bad code".
>> oje
>>
>
>This implementation of TryParse() doesn't solve the problem we were talking 
>about.  The problem is that if an exception is thrown for the common 
>occurrence of malformed args, the result is it is SLOWNESS!  This 
>implementation would fix this problem:
>
>  BOOL TryParse(...args...)
>  {
>        if (!IsValid(args))
>           return FALSE;
>
>           Parse(...);    // Parse() will not throw because args are valid
>           return TRUE;
>  }
>
>
>-- David
> 
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/23/2010 4:02:20 AM

"Joseph M. Newcomer" <newcomer@flounder.com> wrote in message 
news:181326184ejv0jnpda5olkfjjvu54sadln@4ax.com...
> An exact number, expressed in some quantity of nanoseconds, microseconds, 
> or milliseconds
> is essential here.  I don't buy "slowness" unless there is a precise 
> quantity specified.
>

Joe, all I know is the MS architects felt adding TryParse() was necessary in 
..NET 2.0 due to the overhead of Parse() throwing exceptions.  You can take 
it up with them.

-- David 

0
Reply David 6/23/2010 4:17:21 AM

On Jun 22, 5:17=A0pm, "RB" <NoMail@NoSpam> wrote:
> =A0 =A0Additionally I have this logic going so far.
> // in the read loop of MyDoc class serialize
> =A0else =A0 =A0 =A0 =A0 =A0 =A0 =A0
> =A0 =A0{
> =A0 =A0 =A0try
> =A0 =A0 =A0 { =A0 =A0 =A0
> =A0 =A0 =A0 =A0 ar >> FID_Read;; =A0 =A0 =A0// =A0DWORD FID_Read; =A0 =A0=
 =A0 =A0 =A0
> =A0 =A0 =A0 =A0 if (FID_Read !=3D FileID) =A0// const DWORD FileID;
> =A0 =A0 =A0 =A0 =A0 { // FileID mismatch
> =A0 =A0 =A0 =A0 =A0 =A0 throw new CWrongFileIDException(); =A0
> =A0 =A0 =A0 =A0 =A0 }
> =A0 =A0 =A0 =A0 ar >> VerData.Ver >> VerData.CpyRt >> VerData.Corp;
> =A0 =A0 =A0 =A0 ar.SerializeClass(RUNTIME_CLASS(CMapStringToString));
> =A0 =A0 =A0 =A0 ExpMap1.Serialize(ar); =A0 =A0 =A0 =A0 =A0 =A0
> =A0 =A0 =A0 }
> =A0 =A0 =A0catch(CWrongFileIDException* e) =A0 =A0
> =A0 =A0 =A0 {
> =A0 =A0 =A0 =A0 // Do whatever I may need here
> =A0 =A0 =A0 =A0 // so far nothing that I can tell, in fact it seems I cou=
ld have just
> =A0 =A0 =A0 =A0// eliminated my try and catch handlers and just called th=
e
> =A0 =A0 =A0 // =A0AfxThrowArchiveException in the if loop above ?
> =A0 =A0 =A0 =A0 e->Delete( );
> =A0 =A0 =A0 =A0 AfxThrowArchiveException(CArchiveException::badIndex, NUL=
L ); //Invalid file format
> // The above takes me to the exact same cleanup code that I get when
> // I read in a corrupt file (with NO exception code at all ) and mfc hand=
lers it.
> // And leaves me with an untitled filename eliminating the change if inad=
vertant
> // save overwrite.
> =A0 =A0 =A0 }
> =A0 =A0}

As I said: you are not permitted to write try/catch statements ;-)

In this case (wrong "magic" in the file), you have these options
(AFAICanSee):

1. use AfxThrowArchiveException with e.g. badIndex (kinda silly name
given the associated message, but fair enough).

2. (consequence of the ReportSaveLoadException catch I spoke before)
derive your own exception class with whatever info you want, and
override ReportSaveLoadException to handle it. You need to override
it, because ReportSaveLoadException handles only "archive" and "file"
exceptions (doc says it handles "typically a CFileException or
CArchiveException", but it in fact handles these in a more precise
ways, and for the rest it pops up "generic" message, so you might want
to improve on that.

But I'd say that 1 is just fine. At any rate, biggest chance of that
happening is that somebody is jerking up the file intentionally. Do
you want to help these people too much? ;-)

Goran.
0
Reply Goran 6/23/2010 6:49:11 AM

On Jun 22, 7:12=A0pm, Joseph M. Newcomer <newco...@flounder.com> wrote:
> >P.S. Don't forget: you are not allowed to write try/catch
> >statements ;-). If you do, you have 99% chance that you're doing it
> >wrong. Good C++ code of today has RIDICULOUSLY small number of try/
> >catch-es in ti.
>
> ****
> I'm not sure this is a good piece of advice. =A0I use try/catch a lot; it=
 is essentially a
> "non-local GOTO", a structured way of aborting execution and returning to=
 a known place,
> while still guaranteeing that all intermediate destructors for stack vari=
ables are called.

Yes, of course.

I can't speak for you without looking at the code, but I am using
ScopeGuard a lot (it's a heaven sent for exception safety in C++, and
no other language in vicinity comes even close). From the viewpoint of
ScopeGuard, there should be virtually no try/catch statements in the
code, and there should not be catch(...){  whatever(); throw; }
either.

Goran.
0
Reply Goran 6/23/2010 6:53:52 AM

On Jun 22, 9:14=A0pm, "Doug Harrison [MVP]" <d...@mvps.org> wrote:
> On the API designer side, using
> exceptions where return codes are more appropriate forces callers to writ=
e
> try/catch whenever they use the function, so that's a bad use of
> exceptions.

Hey! Tell that to designers of APIs like VCL of Borland or .NET,
then ;-).

On a more serious note... .NET almost exclusively uses exceptions to
report errors and I am aware of one place where, over the time, they
decided to revert to having a non-throwing variant of the function
(TryParse wasn't there in initial .NET versions).

> You never want to turn exception usage into a clumsier version
> of return codes.

That is true. What I wanted to say, I guess, is that even API design
goes well with exceptions, and APIs where it is interesting to have
error-return seem rarer than what one might think from your post.

Goran.
0
Reply Goran 6/23/2010 7:08:25 AM

On Jun 22, 11:06=A0pm, "David Ching" <d...@remove-this.dcsoft.com>
wrote:
> "Doug Harrison [MVP]" <d...@mvps.org> wrote in messagenews:9c1226ldk8g207=
f4asif27nehrcfji6g0e@4ax.com...
>
>
>
> > On Tue, 22 Jun 2010 13:12:33 -0400, Joseph M. Newcomer
> > <newco...@flounder.com> wrote:
>
> >>I'm not sure this is a good piece of advice. =A0I use try/catch a lot; =
it is
> >>essentially a
> >>"non-local GOTO", a structured way of aborting execution and returning =
to
> >>a known place,
> >>while still guaranteeing that all intermediate destructors for stack
> >>variables are called.
> >>It is particularly useful in writing tasks like recursive-descent parse=
rs
> >>(particularly if
> >>you just want to stop without trying to do error recovery, which is alw=
ays
> >>hard) and
> >>terminating threads while still guaranteeing that you return from the
> >>top-level thread
> >>function. =A0It is =A0clean and well-structured way of aborting a
> >>partially-completed
> >>operation. =A0An it is the only way to report errors from operations li=
ke
> >>'new'. =A0Also, look
> >>at the number of exceptions that can be thrown by std:: or boost::.
>
> > Goran was not saying exceptions are bad, just that overly frequent use =
of
> > try/catch is bad, which it usually is. I've been saying for a long long
> > time that there's an inverse relationship between the number of try/cat=
ch
> > clauses you have and the effectiveness with which you're using exceptio=
ns.
> > There are a number of reasons for this. On the API designer side, using
> > exceptions where return codes are more appropriate forces callers to wr=
ite
> > try/catch whenever they use the function, so that's a bad use of
> > exceptions. You never want to turn exception usage into a clumsier vers=
ion
> > of return codes. On the user side, try/catch gets overused when people
> > don't employ the RAII idiom and need to perform clean-up that should be
> > handled by a destructor. Ideally, exceptions are caught far away from
> > where
> > they're thrown, in a top-level handler, which reports the error to the
> > user, logs it, or whatever. It is relatively rare for well-designed cod=
e
> > to
> > need to handle the exception closer to the throw-point.
>
> Not to mention, the overhead of throwing exceptions reduces performance i=
f
> many exceptions are thrown.

I am sorry, I have to press you here. When did you have performance
issues because of that? The thing is, if there's too many exceptions
thrown, there is something wrong with the design. Also, if there
indeed is too many of them, chances are that the code doesn't work
anyhow. If that's the case, does it really matter how fast (or slow)
it doesn't work? You need e.g. some multithreaded code where some
threads eat up too much time because it doesn't work at all and throws
exceptions in a loop.

IOW, situations where one will be concerned about performance aspect
of exceptions are much rarer than one might think from your post. ( I
am getting annoying with this, aren't I?  :-( )

Goran.
0
Reply Goran 6/23/2010 7:15:06 AM

On Jun 23, 1:49=A0am, Joseph M. Newcomer <newco...@flounder.com> wrote:
> Key here is how much you have to do in the catch. =A0Putting all the reco=
very code in the
> catch would consolidate it and eliminate that horror of "goto exit" that =
happens so often.

Hey, +1 for this.

goto is for me forbidden in C++ (but arguably the best approach for
the likes of C).

Goran.
0
Reply Goran 6/23/2010 7:18:56 AM

On 23/06/2010 01:51, Joseph M. Newcomer wrote:

> Note that this could be handled as
>
> BOOL TryParse(...args...)
>      {
>       try
>          {
>           Parse(...);
>           return TRUE;
>          }
>      catch(..whatever..)
>          {
>           return FALSE;
>          }
> }
>
> It ain't rocket science.  And it isn't clear to me how handling the exception results in
> "bad code".

Sure it isn't (ain't?) rocket science... but do you like a fopen that 
throws an exception if the file cannot be opened? No, I prefer one 
returning an error code.
The fact that you can't open a file is not an exceptional condition, and 
I prefer code like:

   if ( some_open_file_api(...) == error )
   {
      ... do what you want... (e.g. create the file, or other stuff...)
   }
   ... normal flow

instead of try/catch.

It was clearly written before: the usefulness of exceptions is inversely 
proportional to the number of try/catch you use: if you clutter your 
code with lots of try/catch then IMHO you are overusing (abusing) 
exceptions.

I think exceptions should be used in *exceptional* conditions (like 
David wrote before).


BTW: I like these articles from the OldNewThing blog:

"Cleaner, more elegant, and wrong"
http://blogs.msdn.com/b/oldnewthing/archive/2004/04/22/118161.aspx

"Cleaner, more elegant, and harder to recognize"
http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx


Giovanni

0
Reply Giovanni 6/23/2010 8:37:23 AM

On 23/06/2010 06:17, David Ching wrote:

> Joe, all I know is the MS architects felt adding TryParse() was
> necessary in .NET 2.0 due to the overhead of Parse() throwing
> exceptions. You can take it up with them.

I do agree with the addition of TryParse:


"Vexing exceptions"

http://blogs.msdn.com/b/ericlippert/archive/2008/09/10/vexing-exceptions.aspx

<quote>

Vexing exceptions are the result of unfortunate design decisions. Vexing 
exceptions are thrown in a completely non-exceptional circumstance, and 
therefore must be caught and handled all the time.

The classic example of a vexing exception is Int32.Parse, which throws 
if you give it a string that cannot be parsed as an integer. But the 99% 
use case for this method is transforming strings input by the user, 
which could be any old thing, and therefore it is in no way exceptional 
for the parse to fail. Worse, there is no way for the caller to 
determine ahead of time whether their argument is bad without 
implementing the entire method themselves, in which case they wouldn't 
need to be calling it in the first place.

This unfortunate design decision was so vexing that of course the 
frameworks team implemented TryParse shortly thereafter which does the 
right thing.

You have to catch vexing exceptions, but doing so is vexing.

Try to never write a library yourself that throws a vexing exception.

</quote>


Giovanni
0
Reply Giovanni 6/23/2010 8:42:44 AM

On Jun 23, 10:37=A0am, Giovanni Dicanio
<giovanniDOTdica...@REMOVEMEgmail.com> wrote:
> Sure it isn't (ain't?) rocket science... but do you like a fopen that
> throws an exception if the file cannot be opened? No, I prefer one
> returning an error code.

Several major frameworks use throwing file open functions and don't
seem to suffer (I know, I argument by number, which is a logical
fallacy ;-))

> The fact that you can't open a file is not an exceptional condition, and
> I prefer code like:
>
> =A0 =A0if ( some_open_file_api(...) =3D=3D error )
> =A0 =A0{
> =A0 =A0 =A0 ... do what you want... (e.g. create the file, or other stuff=
....)
> =A0 =A0}
> =A0 =A0... normal flow
>
> instead of try/catch.

The thing is, IMO: exceptions are not "for exceptional conditions".

They are a way to structure code in face of conditions that normally
cause it to stop whatever it started doing=A9. (Normally, these
conditions are errors, but not necessarily.) They allow us to
__structure code__ in a more clear way.

How is that achieved? Simply by eliminating (out of sight, but not out
of existence, really) a myriad of error paths that do no good except
produce screen garbage. So instead of seeing endless if statements,
you see what code does when it works (and we write the code so that it
works, not to err, don't we?). When you need to see "error" paths, you
look at first enclosing try/catch. When you need to see cleanup code,
you look at destructors of stack objects.

So... IMO, "exceptionality" of the situation matters very little. It's
what happens in WRT code __structure__ that's important.

About your file open operation: typically, you work with file like
this:

open
read/write/rinse/repeat //a lot of code here

Now... If opening a file fails, "a lot of code here" is dead in the
water. So you have a choice of writing an if to stop said code from
running (if open has error result), or doing nothing to stop said code
(if open throws). And if it throws, you are certain that you'll never
forget said "if", because it was done for you.

Now, I suggest that you look at your own code and say honestly, when
you open a file and that fails, do you continue? I am pretty much
certain that in majority of cases you don't continue. So why would you
like these "ifs"?

Goran.

P.S. I mildly like MFC way of having a choice (throwing CFile ctor and
non-throwing ctor + BOOL Open).
0
Reply Goran 6/23/2010 9:35:16 AM

On Jun 23, 6:02=A0am, Joseph M. Newcomer <newco...@flounder.com> wrote:
> Again, the question is performance: if you had to open a file, read data =
in, and finally
> invoke the parsing, what percentage of the time is spent handling an exce=
ption.

Joe, it's true, people have been complaining about said .NET Parse
having considerable impact on performance in at least one place on the
internet, and they were right. They actually went on through the
measurements on their use case (and even wrote their own non-throwing
Parse).

Problem was that they were batch-processing some files, and some of
them had a lot of ill-formatted numbers in them. So they could measure
that use of Parse made code run two times slower (on their use-case,
and clearly, depending on the percentage of these bad numbers). And
note: they were working with files! In fact, IIRC, initially they saw
that "bad" files took more time to process than "good" files - that's
what ticked it all.

Of course, question is why did they have all those bad numbers in the
first place, but hey...

Thing is also that .NET exceptions, like MFC (and VCL) ones, can
really be costly: they are on the heap, they are info-rich (e.g.
there's a CString inside) etc. But despite that, I still say, just
like you: there's no performance problems with exceptions; if there
is, programmer is doing something horribly wrong in 99% of cases ;-).

And absolutely, programmer does not know, by looking at any non-
trivial the code, where it's slow, too!

Goran.
0
Reply Goran 6/23/2010 10:11:04 AM

Hey thanks for replying, this thread picked up while your timezone
was sleeping.  I will respond to this one first and then any other
replies you sent to me if not material already covered here.

> As I said: you are not permitted to write try/catch statements ;-)

  Yes I do remember you saying that but at the time I did not really 
understand what you meant by it other than the fact that most of the 
time it would end up being counterproductive or something to that 
effect.  I get the most from your replies after I experiment thru a 
few foobar attempts and then go back and read them again.

I also remember you saying,

> Find the answer to that, and you'll find that you don't need a try/catch

And I have found the answer to that.

But on your code example,

> try
>  {
>     workworkwork();
>  }
> catch(CException* p)
>  {
>     DEL_ON_EXIT(p);
>    p->ReportError();
>  }

  I see what calling ReportError does. When I tried it in my code 
it just called reported the error but did no cleanup etc, so obviously 
you were obviously explaining " in relation to " here.
   However I would like to express these couple of items here
since I am learning LOADS from all of this.
  First off exactly what is the define DEL_ON_EXIT ? My VC6
compiler doesn't reconize it so I need the include or whatever ?
  Second when I ran this,

catch (CException* e)
 {
   // do Whatever
   e->ReportError( ); runs reports and returns
   throw; // pass it on framework handlers
   // The throw gives me all of what ReportError did and more,
   // including a DELETE_EXCEPTION(e);
   //  so I surmize this is some of what you meant when you said
  //  I should not be using try and catch .
 }

> In this case (wrong "magic" in the file), you have these options
> (AFAICanSee):
> 1. use AfxThrowArchiveException with e.g. badIndex (kinda silly name
> given the associated message, but fair enough).

Yes I had stumbled along until I came up with this,
// in my doc serial load loop
   ar >> FID_Read;;                 
    if (FID_Read != FileID)
     { // FileID mismatch 
        AfxThrowArchiveException(CArchiveException::badIndex, NULL ); 
     }
   ......

This thread took off with so many opinions on try and catch that I lost
track at first. But in summation I learned the syntax I was after and LOADS
of concept. I feel a more confident level dummy 1.0 now
0
Reply RB 6/23/2010 12:54:13 PM

On Jun 23, 2:54=A0pm, "RB" <NoMail@NoSpam> wrote:
> Hey thanks for replying, this thread picked up while your timezone
> was sleeping. =A0I will respond to this one first and then any other
> replies you sent to me if not material already covered here.
>
> > As I said: you are not permitted to write try/catch statements ;-)
>
> =A0 Yes I do remember you saying that but at the time I did not really
> understand what you meant by it other than the fact that most of the
> time it would end up being counterproductive or something to that
> effect. =A0I get the most from your replies after I experiment thru a
> few foobar attempts and then go back and read them again.
>
> I also remember you saying,
>
> > Find the answer to that, and you'll find that you don't need a try/catc=
h
>
> And I have found the answer to that.
>
> But on your code example,
>
> > try
> > =A0{
> > =A0 =A0 workworkwork();
> > =A0}
> > catch(CException* p)
> > =A0{
> > =A0 =A0 DEL_ON_EXIT(p);
> > =A0 =A0p->ReportError();
> > =A0}
>
> =A0 I see what calling ReportError does. When I tried it in my code
> it just called reported the error but did no cleanup etc, so obviously
> you were obviously explaining " in relation to " here.
> =A0 =A0However I would like to express these couple of items here
> since I am learning LOADS from all of this.
> =A0 First off exactly what is the define DEL_ON_EXIT ? My VC6
> compiler doesn't reconize it so I need the include or whatever ?

Ugh. Can't you get a more recent compiler? VC6 - ugh!

About DEL_ON_EXIT: I made it for myself a long time ago, when I
decided that I don't want to meddle with MFC exception macros anymore.
Here it is:

class CMFCExceptionDelete // make it noncopyable
{
public:
  CMFCExceptionDelete(CException* pe) : m_pe(pe) {} // should be
explicit...
  ~CMFCExceptionDelete() { m_pe->Delete(); }
private:
  CException* m_pe;
  void operator=3D(const CMFCExceptionDelete&) {}
  CMFCExceptionDelete(const CMFCExceptionDelete&) {}
};
#define DEL_ON_EXIT(e) CMFCExceptionDelete Delete_e_OnExit(e);

How to use:
....
catch(CException* pe)
{
  DEL_ON_EXIT(pe); // Always a first thing to do in a catch!
  // do anything you like, including throwSomeOtherException
  // don't do throw; or throw pe;
}

That ensures that pe is alive inside catch and that it's pe->Delete()-
d at block exit.

Drawback: you can't hold on to pe after the block exit. If you need
that, find something else ;-).

Goran.
0
Reply Goran 6/23/2010 1:50:23 PM

Today Joe, IMV, its a more a matter of documentation.  The overhead is 
somewhat less important in this "Bulky Code" world, attempting to 
optimize for size or speed is of less important or negligible in a 
already heavy handed OS load environment.  Developing applications in 
a p-code environments are par for the course today.

I think part of the problem for developers is a separation of whats 
critical vs whats natural and/or expected.

Often the complexity (possibly due to lack or complex documentation) 
promotes using a single catch all (more below).

When the components are "better understood" sometimes being explicit 
in exception trapping is useful, other times its not.

Another problem is that constructors do not lend itself for functional 
programming and exceptions are required, if necessary for the class logic.

And of course, as the generation continues, library designers are more 
oops and event programming oriented and thus use less functional 
programming (FP) techniques and sometimes too much oops orientations 
for the simplest of constructs.  As you know, in the early days, good 
library designers (by necessity for the better brand) use to provide 
frameworks for different types of OOPS vs FP programming audience - an 
expensive upkeep in the long run - something has to give, and the 
trend is and has been OOPs, FP mentions gets less attention.  But then 
again, the irony is that you see the same people going back to FP 
technique or adding it, ALA F#.

A good example is my recent experiences with my real first .NET 
project, wcLEX (Wildcat! Live Exchange). I am using this project to 
(re)learn  all the .NET particulars and "How To's" for the more 
expensive product migration move coming.

Not knowing what are all the possible "error" conditions for the .NET 
library, I got into a practice of wrapping try catch around much of 
the code blocks but also working in the Try Catch Finally logic where 
necessary to return negative or positive results.  A good last example 
was adding a search logic using the Regular Expression .NET library.

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
}

This turned out to be nice because for illegal sPattern syntax the 
class throws an exception with detail description of the syntax error. 
  I am glad it did this and not me and it also became a "help" for the 
the user and not something we have to documentation.

In short, 10-15 years ago, my belief in using exception was a crutch 
for not understanding code but also sometimes you had no choice before 
the OOPs class did not lend itself to controlled FP methods. But I 
thought it promoted bad coding overall.

Today, I believe that exception trapping is a vital necessary design 
especially for environments .NET.  There is still the issue of 
programmings not grasp everything, but the throw exceptions are 
"better" or rather design with the intent that developers will use 
them to provide non-critical feedback.

You can get in trouble though when you don't understand the errors. 
This last example is a good illustration where an explicit exception 
catch was used but was a critical abort failure when implemented in a 
different way.

The Windows Live ID SDK has an example implementation where the main 
program.cs has a catch for specific exception handler for

          System.IO.FileNotFoundException

like so:

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Microsoft.Win32;

namespace WindowsLiveIDClientSample
{
     static class Program
     {
         /// <summary>
         /// The main entry point for the application.
         /// </summary>
         [STAThread]
         static void Main()
         {
             Application.EnableVisualStyles();
             Application.SetCompatibleTextRenderingDefault(false);

             try
             {
                 Application.Run(new MainWindow());
             }
             //System requirement detection.
             catch (System.IO.FileNotFoundException fnfex)
             {
                 //Checking for the absence of the Windows Live 
Sign-In Assistant DLL.
                 if (fnfex.Message.Contains("WindowsLive.ID.Client"))
                 {
                     MessageBox.Show("Please install the Windows Live 
ID For Client Applications SDK.");
                 }
                 else
                 {
                     MessageBox.Show(fnfex.Message);
                 }
             }
             finally
             {
                 Application.Exit();
             }
         }
     }
}

Well, if you isolate this LiveID class into your own library and the 
LiveID component was not already installed, then you get an exception 
that is not System.IO.FileNotFoundException.

I learn the hard way that this exception was only correct when the 
LiveID assembly was bound to the EXE and not a helper DLL.

The solution was simple, again, not knowing what are the possible 
specific exceptions, I used catch all instead and checked for the 
"LiveID" string in the exception message.

My take on it.

The sad fact is this - its here. It is what it is, libraries are done 
mostly one way now and developers have no choice but get use to it and 
learn how to work with it.

--
HLS


Joseph M. Newcomer wrote:

> To maximize performance, the Microsoft implementation was designed to create exception
> frames extremely quickly (the try blocks) and it was (I believe rightly) felt that any
> costs required to actually handle the exceptions could be paid at the time the exception
> was thrown.  I think this is a good engineering tradeoff.  So yes, throwing an exception
> is a pretty heavy-duty operation.  But when an error occurs, you are going to be reduced
> to working in "people time" (that is, someone is going to have to read the error message
> and respond to it, integer seconds if not integer tens of seconds) so expending a few
> hundred microseconds (remember, on a 3GHz machine, we can execute as many as 6
> instructions per nanosecond (and that's on the OLD Pentium machines, not the Core
> architectures which can do more), so a microsecond is a *lot* of instructions.  (For those
> of you who don't believe the arithmetic, look up "superscalar architecture").  
> 
> So having exceptions as a basic loop control structure is going to be a Really Bad Idea.
> But frankly, understanding such "spaghetti" code is extremely difficult, and trust me, the
> worst assembler spaghetti code is clear as crystal compared to some of the
> exception-driven code I've had to plow through!  Exceptions are just that: something went
> wrong.
> 			joe
> On Tue, 22 Jun 2010 14:06:56 -0700, "David Ching" <dc@remove-this.dcsoft.com> wrote:
> 
>> "Doug Harrison [MVP]" <dsh@mvps.org> wrote in message 
>> news:9c1226ldk8g207f4asif27nehrcfji6g0e@4ax.com...
>>> On Tue, 22 Jun 2010 13:12:33 -0400, Joseph M. Newcomer
>>> <newcomer@flounder.com> wrote:
>>>
>>>> I'm not sure this is a good piece of advice.  I use try/catch a lot; it is 
>>>> essentially a
>>>> "non-local GOTO", a structured way of aborting execution and returning to 
>>>> a known place,
>>>> while still guaranteeing that all intermediate destructors for stack 
>>>> variables are called.
>>>> It is particularly useful in writing tasks like recursive-descent parsers 
>>>> (particularly if
>>>> you just want to stop without trying to do error recovery, which is always 
>>>> hard) and
>>>> terminating threads while still guaranteeing that you return from the 
>>>> top-level thread
>>>> function.  It is  clean and well-structured way of aborting a 
>>>> partially-completed
>>>> operation.  An it is the only way to report errors from operations like 
>>>> 'new'.  Also, look
>>>> at the number of exceptions that can be thrown by std:: or boost::.
>>> Goran was not saying exceptions are bad, just that overly frequent use of
>>> try/catch is bad, which it usually is. I've been saying for a long long
>>> time that there's an inverse relationship between the number of try/catch
>>> clauses you have and the effectiveness with which you're using exceptions.
>>> There are a number of reasons for this. On the API designer side, using
>>> exceptions where return codes are more appropriate forces callers to write
>>> try/catch whenever they use the function, so that's a bad use of
>>> exceptions. You never want to turn exception usage into a clumsier version
>>> of return codes. On the user side, try/catch gets overused when people
>>> don't employ the RAII idiom and need to perform clean-up that should be
>>> handled by a destructor. Ideally, exceptions are caught far away from 
>>> where
>>> they're thrown, in a top-level handler, which reports the error to the
>>> user, logs it, or whatever. It is relatively rare for well-designed code 
>>> to
>>> need to handle the exception closer to the throw-point.
>>>
>> Not to mention, the overhead of throwing exceptions reduces performance if 
>> many exceptions are thrown.  Exceptions are not meant as a "non-local GOTO". 
>> Exceptions are meant for rarely occurring ERROR conditions (you know, 
>> 'exceptional' conditions!), not normal control flow.  I once saw a switch 
>> statement rewritten as a bunch of thrown exceptions, not a pretty sight.
>>
>> -- David
>>
> Joseph M. Newcomer [MVP]
> email: newcomer@flounder.com
> Web: http://www.flounder.com
> MVP Tips: http://www.flounder.com/mvp_tips.htm

0
Reply Hector 6/23/2010 2:40:54 PM

> Ugh. Can't you get a more recent compiler? VC6 - ugh!

Yea, I can relate to your frustration from a teaching standpoint.
And to infuriate you more, I do now own VC 2005 Pro but have 
not used it much. I am developing all functional apps on the 2005
but still use the VC6 for experimenting because I am so used to
it. Actually other than it's total inability to do a lot of STL items
and lack of strsafe items, I actually like it. But yes I must and
will move on to 2005 totally soon.

> About DEL_ON_EXIT: I made it for myself a long time ago, 
> .........Here it is:

Thanks, I'm going put this into VC and step thru it a few times
so I can get the full impact of it.
Later...........RB
0
Reply RB 6/23/2010 2:58:12 PM

See below...
On Wed, 23 Jun 2010 10:37:23 +0200, Giovanni Dicanio
<giovanniDOTdicanio@REMOVEMEgmail.com> wrote:

>
>On 23/06/2010 01:51, Joseph M. Newcomer wrote:
>
>> Note that this could be handled as
>>
>> BOOL TryParse(...args...)
>>      {
>>       try
>>          {
>>           Parse(...);
>>           return TRUE;
>>          }
>>      catch(..whatever..)
>>          {
>>           return FALSE;
>>          }
>> }
>>
>> It ain't rocket science.  And it isn't clear to me how handling the exception results in
>> "bad code".
>
>Sure it isn't (ain't?) rocket science... but do you like a fopen that 
>throws an exception if the file cannot be opened? No, I prefer one 
>returning an error code.
****
As I said, systems in which APIs throw exceptions are really hard to program.  Exceptions
make sense when you have deep recursion, and need to unwind an unknown and unknowable
amount of recursion all at once.  And are an alternative when you have hundreds of calls
all of which being to look like
	if(!f())
	    return FALSE;
****
>The fact that you can't open a file is not an exceptional condition, and 
>I prefer code like:
>
>   if ( some_open_file_api(...) == error )
>   {
>      ... do what you want... (e.g. create the file, or other stuff...)
>   }
>   ... normal flow
>
>instead of try/catch.
>
>It was clearly written before: the usefulness of exceptions is inversely 
>proportional to the number of try/catch you use: if you clutter your 
>code with lots of try/catch then IMHO you are overusing (abusing) 
>exceptions.
****
So cluttering your code with if-statements is better?  I think the point is that we want
to write code whose complexity is proportional to the task at hand.
****
>
>I think exceptions should be used in *exceptional* conditions (like 
>David wrote before).
****
But one can argue that a file-open failure when the file is expected to exist is, in fact,
an exceptional case...
****
>
>
>BTW: I like these articles from the OldNewThing blog:
>
>"Cleaner, more elegant, and wrong"
>http://blogs.msdn.com/b/oldnewthing/archive/2004/04/22/118161.aspx
>
>"Cleaner, more elegant, and harder to recognize"
>http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx
>
>
>Giovanni
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/23/2010 3:04:18 PM

We just had a piece of code in this NG that looked like this:

HANDLE thread = ::CreateThread(...);
if(thread == NULL)
	::CloseHandle(thread);
DWORD result = ::WaitForSingleObject(thread,...);

now how many errors can you find in the above code?  Closing a NULL handle?  Waiting on a
NULL handle?  This is one of the problems with the if-statement; it *requires* that you
abort the path of execution.  An exception does that automatically.  As I said, this is
all interesting debatable material.
					joe

On Wed, 23 Jun 2010 02:35:16 -0700 (PDT), Goran <goran.pusic@gmail.com> wrote:

>On Jun 23, 10:37�am, Giovanni Dicanio
><giovanniDOTdica...@REMOVEMEgmail.com> wrote:
>> Sure it isn't (ain't?) rocket science... but do you like a fopen that
>> throws an exception if the file cannot be opened? No, I prefer one
>> returning an error code.
>
>Several major frameworks use throwing file open functions and don't
>seem to suffer (I know, I argument by number, which is a logical
>fallacy ;-))
>
>> The fact that you can't open a file is not an exceptional condition, and
>> I prefer code like:
>>
>> � �if ( some_open_file_api(...) == error )
>> � �{
>> � � � ... do what you want... (e.g. create the file, or other stuff...)
>> � �}
>> � �... normal flow
>>
>> instead of try/catch.
>
>The thing is, IMO: exceptions are not "for exceptional conditions".
>
>They are a way to structure code in face of conditions that normally
>cause it to stop whatever it started doing�. (Normally, these
>conditions are errors, but not necessarily.) They allow us to
>__structure code__ in a more clear way.
>
>How is that achieved? Simply by eliminating (out of sight, but not out
>of existence, really) a myriad of error paths that do no good except
>produce screen garbage. So instead of seeing endless if statements,
>you see what code does when it works (and we write the code so that it
>works, not to err, don't we?). When you need to see "error" paths, you
>look at first enclosing try/catch. When you need to see cleanup code,
>you look at destructors of stack objects.
>
>So... IMO, "exceptionality" of the situation matters very little. It's
>what happens in WRT code __structure__ that's important.
>
>About your file open operation: typically, you work with file like
>this:
>
>open
>read/write/rinse/repeat //a lot of code here
>
>Now... If opening a file fails, "a lot of code here" is dead in the
>water. So you have a choice of writing an if to stop said code from
>running (if open has error result), or doing nothing to stop said code
>(if open throws). And if it throws, you are certain that you'll never
>forget said "if", because it was done for you.
>
>Now, I suggest that you look at your own code and say honestly, when
>you open a file and that fails, do you continue? I am pretty much
>certain that in majority of cases you don't continue. So why would you
>like these "ifs"?
>
>Goran.
>
>P.S. I mildly like MFC way of having a choice (throwing CFile ctor and
>non-throwing ctor + BOOL Open).
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/23/2010 3:07:52 PM

"Hector Santos" <sant9442@nospam.gmail.com> wrote in message 
news:OOPShHuELHA.4504@TK2MSFTNGP02.phx.gbl...
> Not knowing what are all the possible "error" conditions for the .NET 
> library, I got into a practice of wrapping try catch around much of the 
> code blocks but also working in the Try Catch Finally logic where 
> necessary to return negative or positive results.  A good last example was 
> adding a search logic using the Regular Expression .NET library.
>
> 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
> }
>
> This turned out to be nice because for illegal sPattern syntax the class 
> throws an exception with detail description of the syntax error. I am glad 
> it did this and not me and it also became a "help" for the the user and 
> not something we have to documentation.
>

You can also set a global unhandled exception handler in your app that will 
display the message box for all exceptions.  This saves you from having to 
put try/catch in so many places, when all you do in the catch is show the 
exception's message.  BTW, the exception also contains a nice callstack 
string, so you can dump the call stack in the message box as well!  :-)



> Today, I believe that exception trapping is a vital necessary design 
> especially for environments .NET.  There is still the issue of 
> programmings not grasp everything, but the throw exceptions are "better" 
> or rather design with the intent that developers will use them to provide 
> non-critical feedback.
>
> You can get in trouble though when you don't understand the errors. This 
> last example is a good illustration where an explicit exception catch was 
> used but was a critical abort failure when implemented in a different way.
>
> The Windows Live ID SDK has an example implementation where the main 
> program.cs has a catch for specific exception handler for
>
>          System.IO.FileNotFoundException
>
> like so:
>
> using System;
> using System.Collections.Generic;
> using System.Windows.Forms;
> using Microsoft.Win32;
>
> namespace WindowsLiveIDClientSample
> {
>     static class Program
>     {
>         /// <summary>
>         /// The main entry point for the application.
>         /// </summary>
>         [STAThread]
>         static void Main()
>         {
>             Application.EnableVisualStyles();
>             Application.SetCompatibleTextRenderingDefault(false);
>
>             try
>             {
>                 Application.Run(new MainWindow());
>             }
>             //System requirement detection.
>             catch (System.IO.FileNotFoundException fnfex)
>             {
>                 //Checking for the absence of the Windows Live Sign-In 
> Assistant DLL.
>                 if (fnfex.Message.Contains("WindowsLive.ID.Client"))
>                 {
>                     MessageBox.Show("Please install the Windows Live ID 
> For Client Applications SDK.");
>                 }
>                 else
>                 {
>                     MessageBox.Show(fnfex.Message);
>                 }
>             }
>             finally
>             {
>                 Application.Exit();
>             }
>         }
>     }
> }
>
> Well, if you isolate this LiveID class into your own library and the 
> LiveID component was not already installed, then you get an exception that 
> is not System.IO.FileNotFoundException.
>
> I learn the hard way that this exception was only correct when the LiveID 
> assembly was bound to the EXE and not a helper DLL.
>
> The solution was simple, again, not knowing what are the possible specific 
> exceptions, I used catch all instead and checked for the "LiveID" string 
> in the exception message.
>

To be fair, this same problem would have happened if error codes were 
returned instead of exceptions thrown.  (I.e. you may not understand when 
and under what circumstances various error codes are returned vs. when and 
under what circumstances various exceptions are thrown.)  It's the same 
thing.



> The sad fact is this - its here. It is what it is, libraries are done 
> mostly one way now and developers have no choice but get use to it and 
> learn how to work with it.
>

For me, exceptions offer a way of stepping back and recovering from "various 
errors" without tediously checking each step along the way.  Theoretically 
they conserve brain power.  But the downside is you give up explicit control 
that you intrinsically get when you are forced to check error codes with 
nested if.  So you spend at least some of the saved brain power 
understanding and ensuring you cover the various situations, sometimes by 
trial and error, as you say.  For me becoming a .NET programmer, the main 
question is, do you want to spend brain power making sure you work well with 
the framework, or do you want to spend brain power tediously coding each 
possible little thing in MFC.  This is why I say .NET makes MFC look like 
assembly language, with the advantages and disadvantages of such.

-- David
 

0
Reply David 6/23/2010 3:24:20 PM

"Giovanni Dicanio" <giovanniDOTdicanio@REMOVEMEgmail.com> wrote in message 
news:eDb2QArELHA.4120@TK2MSFTNGP02.phx.gbl...
> "Vexing exceptions"
>
> http://blogs.msdn.com/b/ericlippert/archive/2008/09/10/vexing-exceptions.aspx
>

Great article and illustrative of what we were trying to say!

-- David 

0
Reply David 6/23/2010 3:25:22 PM

"Goran" <goran.pusic@gmail.com> wrote in message 
news:d5d4107e-3b75-4a3f-be81-45c2c0d916a2@d37g2000yqm.googlegroups.com...
> Thing is also that .NET exceptions, like MFC (and VCL) ones, can
> really be costly: they are on the heap, they are info-rich (e.g.
> there's a CString inside) etc. But despite that, I still say, just
> like you: there's no performance problems with exceptions; if there
> is, programmer is doing something horribly wrong in 99% of cases ;-).
>
> And absolutely, programmer does not know, by looking at any non-
> trivial the code, where it's slow, too!
>

Hi Goran, well I understand your point.  My favorite string class is 
CString, and I use it by default.  But I once had a situation on startup 
where the profiler showed a lot of time in copying CString, so we replaced a 
few lines of code to use lstrcpy() instead of CString, and that saved 
significant time.  So I understand your point that exceptions in general are 
very usable, but it's only in certain situations where they cause a 
noticeable problem.

And perhaps .NET exceptions are more costly than C++ ones, I don't know.  (I 
didn't use exceptions in C++, I only started using them because I had no 
choice when I went to .NET.)  I will say it is a common in .NET programming 
to run in the debugger with first chance exceptions being enabled so you are 
well aware of any exceptions being thrown.  And when I eliminate those, the 
program does seem to run a bit faster, but I don't know if that is my 
imagination or not.  It does seem avoiding unnecessary exceptions is 
emphasized more in .NET, but I always thought that was because they are used 
more in .NET.  Also perhaps because it involves loading more assemblies to 
deal with the exception, and loading assemblies is expensive.

Thanks,
David 

0
Reply David 6/23/2010 3:31:32 PM

On 23/06/2010 17:39, Hector Santos wrote:

> Another problem is that constructors do not lend itself for functional
> programming and exceptions are required, if necessary for the class logic.

Note that there is an alternative design: two-step construction.
(This is widely used in MFC as well, e.g. CWnd default constructor 
basically puts the object in a safe state, but then you need to call 
CWnd::Create/CreateEx).

With two-step construction you don't need to throw exception in ctor, 
because the default ctor just puts the object in a safe state (e.g. zero 
the pointers, etc.) and the actual construction is done in a /ad hoc/ 
construction method (e.g. Init(), Create()...).

Note also that if you throw an exception in the ctor, the destructor is 
*not* called! So, to write exception-safe code, you should pay attention 
to this point and provide proper cleanup code in ctor as well.
This is bad, IMHO.
But this problem doesn't occure in two-step construction: in fact, the 
default ctor doesn't throw, and if the Init()/Create() construction 
method throws, the destructor is properly called.

Moreover, you can't call (or is it not safe to call...) virtual methods 
in a ctor; but you can call virtual methods in an Init()/Create() 
method, after the default ctor put the object in a safe state.

I like the two-step construction pattern for C++, and I listed above 
some reasons (even if the C++-FAQ discourages its use).


Giovanni

0
Reply Giovanni 6/23/2010 3:39:12 PM

On 23/06/2010 17:39, Hector Santos 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
> }
>
> This turned out to be nice

catching(Exception) in C# is like catch(...) in C++: basically you are 
swallowing everything... but IMHO you should only process Regex related 
exception.

I don't know the details of .NET Regex, but I think they should have 
designed an /ad hoc/ exception class for regex (e.g. RegexError), so 
that you could selectively catch RegexError and not swallow unrelated 
exceptions.

Note also that C# exceptions are better designed than C++ ones.
For example, you can put localized strings in C# exceptions, it is 
possible to nest C# exceptions (see e.g. Exception.InnerException 
property) to provide better diagnosis, etc.

Giovanni
0
Reply Giovanni 6/23/2010 3:44:22 PM

One of the undocumented and painful features of the Automation interface to Office is that
it throws exceptions when there is an error.  I handled this by the following technique:

WHERE here;
try {
    HERE();
    SomeAutomationCall(...);
    ... stuff
    HERE();
    SomeOtherAutomationCall(...);
    ...(repeat above pattern several times)...
   }
catch(COleException * e) // or some remarkably similar name...
   {
    ReportOleException(e, here);
    ...
    return FALSE;
   }
return TRUE;

where HERE() stored in the variable (which had to be called 'here') _T(__FILE__) and
__LINE__+1, so the ReportOleException could tell me which line failed.  This only worked
because I was able to "lump" all my Automation calls into a single "atomic" (from the
viewpoint of error-handling) sequence.  But it made debugging hell.  It doesn't help that
the VBA documentation for the internal structures of PowerPoint is among the worst
documention Microsoft has ever written.  The most polite thing that can be said about it
is "totally incoherent".
				joe

On Wed, 23 Jun 2010 11:39:21 -0400, Hector Santos <sant9442@nospam.gmail.com> wrote:

>Today Joe, IMV, its a more a matter of documentation.  The overhead is 
>somewhat less important in this "Bulky Code" world, attempting to 
>optimize for size or speed is of less important or negligible in a 
>already heavy handed OS load environment.  Developing applications in 
>a p-code environments are par for the course today.
>
>I think part of the problem for developers is a separation of whats 
>critical vs whats natural and/or expected.
>
>Often the complexity (possibly due to lack or complex documentation) 
>promotes using a single catch all (more below).
>
>When the components are "better understood" sometimes being explicit 
>in exception trapping is useful, other times its not.
>
>Another problem is that constructors do not lend itself for functional 
>programming and exceptions are required, if necessary for the class logic.
>
>And of course, as the generation continues, library designers are more 
>oops and event programming oriented and thus use less functional 
>programming (FP) techniques and sometimes too much oops orientations 
>for the simplest of constructs.  As you know, in the early days, good 
>library designers (by necessity for the better brand) use to provide 
>frameworks for different types of OOPS vs FP programming audience - an 
>expensive upkeep in the long run - something has to give, and the 
>trend is and has been OOPs, FP mentions gets less attention.  But then 
>again, the irony is that you see the same people going back to FP 
>technique or adding it, ALA F#.
>
>A good example is my recent experiences with my real first .NET 
>project, wcLEX (Wildcat! Live Exchange). I am using this project to 
>(re)learn  all the .NET particulars and "How To's" for the more 
>expensive product migration move coming.
>
>Not knowing what are all the possible "error" conditions for the .NET 
>library, I got into a practice of wrapping try catch around much of 
>the code blocks but also working in the Try Catch Finally logic where 
>necessary to return negative or positive results.  A good last example 
>was adding a search logic using the Regular Expression .NET library.
>
>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
>}
>
>This turned out to be nice because for illegal sPattern syntax the 
>class throws an exception with detail description of the syntax error. 
>  I am glad it did this and not me and it also became a "help" for the 
>the user and not something we have to documentation.
>
>In short, 10-15 years ago, my belief in using exception was a crutch 
>for not understanding code but also sometimes you had no choice before 
>the OOPs class did not lend itself to controlled FP methods. But I 
>thought it promoted bad coding overall.
>
>Today, I believe that exception trapping is a vital necessary design 
>especially for environments .NET.  There is still the issue of 
>programmings not grasp everything, but the throw exceptions are 
>"better" or rather design with the intent that developers will use 
>them to provide non-critical feedback.
>
>You can get in trouble though when you don't understand the errors. 
>This last example is a good illustration where an explicit exception 
>catch was used but was a critical abort failure when implemented in a 
>different way.
>
>The Windows Live ID SDK has an example implementation where the main 
>program.cs has a catch for specific exception handler for
>
>          System.IO.FileNotFoundException
>
>like so:
>
>using System;
>using System.Collections.Generic;
>using System.Windows.Forms;
>using Microsoft.Win32;
>
>namespace WindowsLiveIDClientSample
>{
>     static class Program
>     {
>         /// <summary>
>         /// The main entry point for the application.
>         /// </summary>
>         [STAThread]
>         static void Main()
>         {
>             Application.EnableVisualStyles();
>             Application.SetCompatibleTextRenderingDefault(false);
>
>             try
>             {
>                 Application.Run(new MainWindow());
>             }
>             //System requirement detection.
>             catch (System.IO.FileNotFoundException fnfex)
>             {
>                 //Checking for the absence of the Windows Live 
>Sign-In Assistant DLL.
>                 if (fnfex.Message.Contains("WindowsLive.ID.Client"))
>                 {
>                     MessageBox.Show("Please install the Windows Live 
>ID For Client Applications SDK.");
>                 }
>                 else
>                 {
>                     MessageBox.Show(fnfex.Message);
>                 }
>             }
>             finally
>             {
>                 Application.Exit();
>             }
>         }
>     }
>}
>
>Well, if you isolate this LiveID class into your own library and the 
>LiveID component was not already installed, then you get an exception 
>that is not System.IO.FileNotFoundException.
>
>I learn the hard way that this exception was only correct when the 
>LiveID assembly was bound to the EXE and not a helper DLL.
>
>The solution was simple, again, not knowing what are the possible 
>specific exceptions, I used catch all instead and checked for the 
>"LiveID" string in the exception message.
>
>My take on it.
>
>The sad fact is this - its here. It is what it is, libraries are done 
>mostly one way now and developers have no choice but get use to it and 
>learn how to work with it.
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/23/2010 5:21:02 PM

Actually, I have not only written hundreds of thousands of lines of C code without a goto
(perhaps, actually, in excess of a million), but have managed to take goto code and remove
the gotos.
				joe

On Wed, 23 Jun 2010 00:18:56 -0700 (PDT), Goran <goran.pusic@gmail.com> wrote:

>On Jun 23, 1:49�am, Joseph M. Newcomer <newco...@flounder.com> wrote:
>> Key here is how much you have to do in the catch. �Putting all the recovery code in the
>> catch would consolidate it and eliminate that horror of "goto exit" that happens so often.
>
>Hey, +1 for this.
>
>goto is for me forbidden in C++ (but arguably the best approach for
>the likes of C).
>
>Goran.
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/23/2010 5:22:14 PM

Good Point Giovanni.

Off hand, as you mentioned this, my mind is thinking the Two step 
approach was common with Borland Pascal Oops or POOP as I use to call 
it. <g>

But I never really understood why a FP approach was not a big 
consideration for construction:

    SomeClass *sc = new SomeClass();
    if (sc == NULL) {
        //some constructor error occurred
    }

I guess you could do a macro, template or something if you wanted this.

--

Giovanni Dicanio wrote:

> On 23/06/2010 17:39, Hector Santos wrote:
> 
>> Another problem is that constructors do not lend itself for functional
>> programming and exceptions are required, if necessary for the class 
>> logic.
> 
> Note that there is an alternative design: two-step construction.
> (This is widely used in MFC as well, e.g. CWnd default constructor 
> basically puts the object in a safe state, but then you need to call 
> CWnd::Create/CreateEx).
> 
> With two-step construction you don't need to throw exception in ctor, 
> because the default ctor just puts the object in a safe state (e.g. zero 
> the pointers, etc.) and the actual construction is done in a /ad hoc/ 
> construction method (e.g. Init(), Create()...).
> 
> Note also that if you throw an exception in the ctor, the destructor is 
> *not* called! So, to write exception-safe code, you should pay attention 
> to this point and provide proper cleanup code in ctor as well.
> This is bad, IMHO.
> But this problem doesn't occure in two-step construction: in fact, the 
> default ctor doesn't throw, and if the Init()/Create() construction 
> method throws, the destructor is properly called.
> 
> Moreover, you can't call (or is it not safe to call...) virtual methods 
> in a ctor; but you can call virtual methods in an Init()/Create() 
> method, after the default ctor put the object in a safe state.
> 
> I like the two-step construction pattern for C++, and I listed above 
> some reasons (even if the C++-FAQ discourages its use).
> 
> 
> Giovanni
> 



-- 
HLS
0
Reply Hector 6/23/2010 5:50:54 PM

Giovanni Dicanio wrote:

> On 23/06/2010 17:39, Hector Santos 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
>> }
>>
>> This turned out to be nice
> 
> catching(Exception) in C# is like catch(...) in C++: basically you are 
> swallowing everything... but IMHO you should only process Regex related 
> exception.
> 
> I don't know the details of .NET Regex, but I think they should have 
> designed an /ad hoc/ exception class for regex (e.g. RegexError), so 
> that you could selectively catch RegexError and not swallow unrelated 
> exceptions.
> 
> Note also that C# exceptions are better designed than C++ ones.
> For example, you can put localized strings in C# exceptions, it is 
> possible to nest C# exceptions (see e.g. Exception.InnerException 
> property) to provide better diagnosis, etc.
> 
> Giovanni


You see, you made my point, one has to be knowledgable of the error 
exceptions and traps for each class in order to consider specific 
trappings. :)

But as I also pointed out, I came across where using the specific 
trapping MAY only apply to a specific binding or integration.

Yes, when I was diagnosing and debugging the issue I came across with 
the Live ID reference assembly from a DLL rather than the example 
usage with a direct reference in the EXE example, I studied up on the 
exception levels and inner exception stuff.

I figured, atleast for now, I can cover both usages with the Live ID 
SDK DLL is bound to an EXE or my helper DLL using the catch all.

I saw it somewhat of a chicken and egg situation for general 
applicability.  If a DLL is missing, then any specific DLL Exception 
class will not be available, hence the critical abort.

I have to go back to verify what happen and what I found under debug, 
but I think that is what happen here.

In my helper DLL, I have a InitializeWindowsLive() class method:

    private bool InitializeWindowsLive()
    {
       try
       {
          oIDMgr = IdentityManager.CreateInstance(AppId, AppName);
          return oIDMgr != null;
       }
       catch (WLLogOnException wlex)
       {
          ShowError("WLLogOnException: {0}",wlex.message);
       }
       catch (Exception ex)
       {
          ShowError("InitializeWindowsLive(): {0}" + ex.Message);
       }
       return false;
    }

When Program.cs had the original usage of the SDK example using the 
System.IO.FileNotFoundException catch only, I guess delayed loading 
occurred when the LiveID DLL was bound to the EXE.  Hence this catch 
would work.

But I used a helper DLL and the LiveID DLL was bound to it, the 
InitializeWindowsLive() error if I remember was that the 
WLogOnException was not found because the DLL was not found.

I don't remember if I had the 2nd catch in the Initialize function or 
it was part of the solution, but for sure the program.cs could not use 
the System.IO.FileNotFoundException catch. I had tried to use the 
InnerException too I recall, overall I was dumping everything to see 
what I can "hold on" too to catch the overall error of the separate 
LiveID DLL not being installed on user machine.

The point is that even using specific exceptions for the library MAY 
NOT work if the library itself is missing.

I MAY or MAY NOT be saying that using a catch all may be necessary 
MOST of the time.

-- 
HLS
0
Reply Hector 6/23/2010 6:12:56 PM

David Ching wrote:

> You can also set a global unhandled exception handler in your app that 
> will display the message box for all exceptions.  This saves you from 
> having to put try/catch in so many places, when all you do in the catch 
> is show the exception's message.  BTW, the exception also contains a 
> nice callstack string, so you can dump the call stack in the message box 
> as well!  :-)


Yes, I know that much.  At some point, I am going to write a generic 
error logging/display class for recording/sending mechanism for 
end-users.  Right now I am just getting a feel for .NET learning all 
the basic needs and I would probably be re-inventing this too when I 
cross that bridge.

Today, for our server I ave RecordError class that allows Event 
recording and/or basic file recording with sysop signaling, paging 
options, etc.

>> The solution was simple, again, not knowing what are the possible 
>> specific exceptions, I used catch all instead and checked for the 
>> "LiveID" string in the exception message.
>>
> 
> To be fair, this same problem would have happened if error codes were 
> returned instead of exceptions thrown.  (I.e. you may not understand 
> when and under what circumstances various error codes are returned vs. 
> when and under what circumstances various exceptions are thrown.)  It's 
> the same thing.


Sure, like a LoadLibrary() with indirect loading.  You an error for 
your DLL, not necesarily knowing what dll it tried to load.  DEPENDS 
helps help.

>> The sad fact is this - its here. It is what it is, libraries are done 
>> mostly one way now and developers have no choice but get use to it and 
>> learn how to work with it.
>>
> 
> For me, exceptions offer a way of stepping back and recovering from 
> "various errors" without tediously checking each step along the way.  
> Theoretically they conserve brain power.  But the downside is you give 
> up explicit control that you intrinsically get when you are forced to 
> check error codes with nested if.  So you spend at least some of the 
> saved brain power understanding and ensuring you cover the various 
> situations, sometimes by trial and error, as you say.  For me becoming a 
> .NET programmer, the main question is, do you want to spend brain power 
> making sure you work well with the framework, or do you want to spend 
> brain power tediously coding each possible little thing in MFC.  This is 
> why I say .NET makes MFC look like assembly language, with the 
> advantages and disadvantages of such.


Good way of putting - conserving brain power.  I have to agree with 
you there.  For me, succumbing to .NET is not worrying about the 
million DLL it depends on and loads. I was looking at Process Explorer 
today just for wcLEX and comparing how nice my native apps are more 
streamlined, but there again, the OS HOOKS are applied and thats 
basically why I given in.  Not worrying about the overhead.

PS: Glad you are no longer mad at me. :)

-- 
HLS
0
Reply Hector 6/23/2010 6:32:53 PM

"Hector Santos" <sant9442@nospam.gmail.com> wrote in message 
news:u5Xw8IwELHA.3732@TK2MSFTNGP02.phx.gbl...
> PS: Glad you are no longer mad at me. :)
>

The nice thing about being a developer and technical discussions is that 
programming truth transcends all else!  :-)

-- David 

0
Reply David 6/23/2010 6:41:50 PM

Good observations, all!
			joe
On Wed, 23 Jun 2010 17:39:12 +0200, Giovanni Dicanio
<giovanniDOTdicanio@REMOVEMEgmail.com> wrote:

>On 23/06/2010 17:39, Hector Santos wrote:
>
>> Another problem is that constructors do not lend itself for functional
>> programming and exceptions are required, if necessary for the class logic.
>
>Note that there is an alternative design: two-step construction.
>(This is widely used in MFC as well, e.g. CWnd default constructor 
>basically puts the object in a safe state, but then you need to call 
>CWnd::Create/CreateEx).
>
>With two-step construction you don't need to throw exception in ctor, 
>because the default ctor just puts the object in a safe state (e.g. zero 
>the pointers, etc.) and the actual construction is done in a /ad hoc/ 
>construction method (e.g. Init(), Create()...).
>
>Note also that if you throw an exception in the ctor, the destructor is 
>*not* called! So, to write exception-safe code, you should pay attention 
>to this point and provide proper cleanup code in ctor as well.
>This is bad, IMHO.
>But this problem doesn't occure in two-step construction: in fact, the 
>default ctor doesn't throw, and if the Init()/Create() construction 
>method throws, the destructor is properly called.
>
>Moreover, you can't call (or is it not safe to call...) virtual methods 
>in a ctor; but you can call virtual methods in an Init()/Create() 
>method, after the default ctor put the object in a safe state.
>
>I like the two-step construction pattern for C++, and I listed above 
>some reasons (even if the C++-FAQ discourages its use).
>
>
>Giovanni
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/23/2010 6:57:04 PM

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.

For example, opening a file with append mode. Traditionally, the file 
is open/creating with a FILE SHARE READ/WRITE mode.

This is not the case any more with .NET.  The StreamWriter constructor:

        StreamWriter(string filename, bool Append)

opens the file in FileShare.Read mode only.

Whats funny is that I asked this question in MS FORUMS and someone 
came back suggestion that 95% scenarios this is expected usage and I 
represent 5% scenarios.

I suggested that for C/C++ developers migrating to .NET, it would be a 
  higher expectation that opening a file or stream in append mode is 
atomic and Read/Write Share mode simply because that is what they are 
use to.

Anyway, my point here is that in C/C++ I don't need an exception trap 
for fopen() based appending which I had to add in .NET to find out 
what was going on, and after I found out and changed the code so open 
the file first in FileShare.ReadWrite mode and pass this to 
StreamWrite, I decided to keep the trap in to cover other possible 
sceanario, like OUT OF DISK space :)

--


Giovanni Dicanio wrote:

> On 23/06/2010 01:51, Joseph M. Newcomer wrote:
> 
>> Note that this could be handled as
>>
>> BOOL TryParse(...args...)
>>      {
>>       try
>>          {
>>           Parse(...);
>>           return TRUE;
>>          }
>>      catch(..whatever..)
>>          {
>>           return FALSE;
>>          }
>> }
>>
>> It ain't rocket science.  And it isn't clear to me how handling the 
>> exception results in
>> "bad code".
> 
> Sure it isn't (ain't?) rocket science... but do you like a fopen that 
> throws an exception if the file cannot be opened? No, I prefer one 
> returning an error code.
> The fact that you can't open a file is not an exceptional condition, and 
> I prefer code like:
> 
>   if ( some_open_file_api(...) == error )
>   {
>      ... do what you want... (e.g. create the file, or other stuff...)
>   }
>   ... normal flow
> 
> instead of try/catch.
> 
> It was clearly written before: the usefulness of exceptions is inversely 
> proportional to the number of try/catch you use: if you clutter your 
> code with lots of try/catch then IMHO you are overusing (abusing) 
> exceptions.
> 
> I think exceptions should be used in *exceptional* conditions (like 
> David wrote before).
> 
> 
> BTW: I like these articles from the OldNewThing blog:
> 
> "Cleaner, more elegant, and wrong"
> http://blogs.msdn.com/b/oldnewthing/archive/2004/04/22/118161.aspx
> 
> "Cleaner, more elegant, and harder to recognize"
> http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx
> 
> 
> Giovanni
> 



-- 
HLS
0
Reply Hector 6/23/2010 7:00:53 PM

One of the colossal failures of FP was that in its early incarnataions, it was
"side-effect-free" code, which makes you wonder why you would ever want to bother
executing it at all.  When FP was coming into style, it was all about having no side
effects, which meant that if your code ran for a year, it had the same effect as if it had
not run at all, so you could save a lot of computer time by typing it in and never
executing it.

Haskell and other modern FP languages have a complex matrix of side effects, from the
"unsafe" writes-to-a-file types to the pure functions.

I have always been somewhere in the middle; a function should either be executed solely
for its side effects (changes in the program's internal state or data's external state,
such as a file, the Registry, etc.) or it should be truly pure functional code, with all
"side effects" happening solely to its parameter values (e.g., CString &) or expressed in
its return result.

I also believe that when external state is affected, that the behavior must be
transactional, that is, either it writes to the file or it does not write to the file, but
it NEVER writes partial information to the file (and we can debate what should happen on
"disk full" errors).  I'm less of a stickler for parameter effects, and I'm willing to
accept "If this function returns TRUE, then the CString & contains the result, but if this
function returns FALSE, the CString & contents are not defined", and I would never pass in
other than a temporary CString reference in such a case (upon returning TRUE, I might
"commit" that result to the internal program state by doing an assignment, but I would
never pass in a direct reference to the program state CString).  

Methods which interact do so through member variables of the class that contains them, and
this state is invisible outside the class (it must always be, at worst, "protected", and
maybe even "private")

Therefore, I see exceptions as a way of executing something of the form
	{wp() f() assert(oc)}
where wp() is the weakest preconditions tor successful execution of f, f does the
computation, and oc is the set of output predicates that must be true.  Thus, I view an
exception as something limited to the {} above, and which can be thrown by wp(), by f(),
or by the assert(oc), but which always transfers control out of the {} set.  In the pure
FP model, an exception terminates the top-level function.  
				joe

				joe

On Wed, 23 Jun 2010 14:49:30 -0400, Hector Santos <sant9442@nospam.gmail.com> wrote:

>Good Point Giovanni.
>
>Off hand, as you mentioned this, my mind is thinking the Two step 
>approach was common with Borland Pascal Oops or POOP as I use to call 
>it. <g>
>
>But I never really understood why a FP approach was not a big 
>consideration for construction:
>
>    SomeClass *sc = new SomeClass();
>    if (sc == NULL) {
>        //some constructor error occurred
>    }
>
>I guess you could do a macro, template or something if you wanted this.
>
>--
>
>Giovanni Dicanio wrote:
>
>> On 23/06/2010 17:39, Hector Santos wrote:
>> 
>>> Another problem is that constructors do not lend itself for functional
>>> programming and exceptions are required, if necessary for the class 
>>> logic.
>> 
>> Note that there is an alternative design: two-step construction.
>> (This is widely used in MFC as well, e.g. CWnd default constructor 
>> basically puts the object in a safe state, but then you need to call 
>> CWnd::Create/CreateEx).
>> 
>> With two-step construction you don't need to throw exception in ctor, 
>> because the default ctor just puts the object in a safe state (e.g. zero 
>> the pointers, etc.) and the actual construction is done in a /ad hoc/ 
>> construction method (e.g. Init(), Create()...).
>> 
>> Note also that if you throw an exception in the ctor, the destructor is 
>> *not* called! So, to write exception-safe code, you should pay attention 
>> to this point and provide proper cleanup code in ctor as well.
>> This is bad, IMHO.
>> But this problem doesn't occure in two-step construction: in fact, the 
>> default ctor doesn't throw, and if the Init()/Create() construction 
>> method throws, the destructor is properly called.
>> 
>> Moreover, you can't call (or is it not safe to call...) virtual methods 
>> in a ctor; but you can call virtual methods in an Init()/Create() 
>> method, after the default ctor put the object in a safe state.
>> 
>> I like the two-step construction pattern for C++, and I listed above 
>> some reasons (even if the C++-FAQ discourages its use).
>> 
>> 
>> Giovanni
>> 
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/23/2010 7:08:21 PM

In fact, you can argue that RegExError is actually a list of exceptions
	RegExSyntaxError
	RegExMatchFailure
	RegExInternalError
and possibly others.  I need to know WHY the regex failed.  For example, in the FreeBSD
code there are a whole lot of different syntax errors (bad pattern syntax, ^ not appearing
on left of pattern, $ not appearing on right of pattern, extra ')', missing ')', etc.) and
a collection of fialures during pattern matching, all of which require different responses
from the user.

In my implementaiton, I split up the parsing of the regexp from the execution of the match
and the replacement of the patterns, and can handle errors for each of them separately.
				joe
n
On Wed, 23 Jun 2010 17:44:22 +0200, Giovanni Dicanio
<giovanniDOTdicanio@REMOVEMEgmail.com> wrote:

>On 23/06/2010 17:39, Hector Santos 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
>> }
>>
>> This turned out to be nice
>
>catching(Exception) in C# is like catch(...) in C++: basically you are 
>swallowing everything... but IMHO you should only process Regex related 
>exception.
>
>I don't know the details of .NET Regex, but I think they should have 
>designed an /ad hoc/ exception class for regex (e.g. RegexError), so 
>that you could selectively catch RegexError and not swallow unrelated 
>exceptions.
>
>Note also that C# exceptions are better designed than C++ ones.
>For example, you can put localized strings in C# exceptions, it is 
>possible to nest C# exceptions (see e.g. Exception.InnerException 
>property) to provide better diagnosis, etc.
>
>Giovanni
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/23/2010 7:12:00 PM

I used strsafe.h in VS6 for many years, and it worked quite well.
				joe

On Wed, 23 Jun 2010 10:58:12 -0400, "RB" <NoMail@NoSpam> wrote:

>
>> Ugh. Can't you get a more recent compiler? VC6 - ugh!
>
>Yea, I can relate to your frustration from a teaching standpoint.
>And to infuriate you more, I do now own VC 2005 Pro but have 
>not used it much. I am developing all functional apps on the 2005
>but still use the VC6 for experimenting because I am so used to
>it. Actually other than it's total inability to do a lot of STL items
>and lack of strsafe items, I actually like it. But yes I must and
>will move on to 2005 totally soon.
>
>> About DEL_ON_EXIT: I made it for myself a long time ago, 
>> .........Here it is:
>
>Thanks, I'm going put this into VC and step thru it a few times
>so I can get the full impact of it.
>Later...........RB
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/23/2010 7:12:50 PM

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.

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.

Maybe with FP, exception trapping could now be considered even more 
important because in classic FP, its not something you think about, 
you can't if you wish to stack commands which is also the same idea 
with OOPS based protocol stacking. So you need the external wrapping 
and help to deal with this extraneous circumstances.

But then again, APL was a interpreted environment so you had the RTE 
around to provide the critical unforeseen trappings for you.

I think that is an important point in all this, in C/C++ or native 
languages, you don't have that RTE around.  In .NET or similar CLR 
environments you do.  So you might not be handling a possible error 
condition yourself, but the RTE does have the "global catch."

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 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. :)

--

Joseph M. Newcomer wrote:

> One of the colossal failures of FP was that in its early incarnataions, it was
> "side-effect-free" code, which makes you wonder why you would ever want to bother
> executing it at all.  When FP was coming into style, it was all about having no side
> effects, which meant that if your code ran for a year, it had the same effect as if it had
> not run at all, so you could save a lot of computer time by typing it in and never
> executing it.
> 
> Haskell and other modern FP languages have a complex matrix of side effects, from the
> "unsafe" writes-to-a-file types to the pure functions.
> 
> I have always been somewhere in the middle; a function should either be executed solely
> for its side effects (changes in the program's internal state or data's external state,
> such as a file, the Registry, etc.) or it should be truly pure functional code, with all
> "side effects" happening solely to its parameter values (e.g., CString &) or expressed in
> its return result.
> 
> I also believe that when external state is affected, that the behavior must be
> transactional, that is, either it writes to the file or it does not write to the file, but
> it NEVER writes partial information to the file (and we can debate what should happen on
> "disk full" errors).  I'm less of a stickler for parameter effects, and I'm willing to
> accept "If this function returns TRUE, then the CString & contains the result, but if this
> function returns FALSE, the CString & contents are not defined", and I would never pass in
> other than a temporary CString reference in such a case (upon returning TRUE, I might
> "commit" that result to the internal program state by doing an assignment, but I would
> never pass in a direct reference to the program state CString).  
> 
> Methods which interact do so through member variables of the class that contains them, and
> this state is invisible outside the class (it must always be, at worst, "protected", and
> maybe even "private")
> 
> Therefore, I see exceptions as a way of executing something of the form
> 	{wp() f() assert(oc)}
> where wp() is the weakest preconditions tor successful execution of f, f does the
> computation, and oc is the set of output predicates that must be true.  Thus, I view an
> exception as something limited to the {} above, and which can be thrown by wp(), by f(),
> or by the assert(oc), but which always transfers control out of the {} set.  In the pure
> FP model, an exception terminates the top-level function.  
> 				joe
> 
> 				joe
> 
> On Wed, 23 Jun 2010 14:49:30 -0400, Hector Santos <sant9442@nospam.gmail.com> wrote:
> 
>> Good Point Giovanni.
>>
>> Off hand, as you mentioned this, my mind is thinking the Two step 
>> approach was common with Borland Pascal Oops or POOP as I use to call 
>> it. <g>
>>
>> But I never really understood why a FP approach was not a big 
>> consideration for construction:
>>
>>    SomeClass *sc = new SomeClass();
>>    if (sc == NULL) {
>>        //some constructor error occurred
>>    }
>>
>> I guess you could do a macro, template or something if you wanted this.
>>
>> --
>>
>> Giovanni Dicanio wrote:
>>
>>> On 23/06/2010 17:39, Hector Santos wrote:
>>>
>>>> Another problem is that constructors do not lend itself for functional
>>>> programming and exceptions are required, if necessary for the class 
>>>> logic.
>>> Note that there is an alternative design: two-step construction.
>>> (This is widely used in MFC as well, e.g. CWnd default constructor 
>>> basically puts the object in a safe state, but then you need to call 
>>> CWnd::Create/CreateEx).
>>>
>>> With two-step construction you don't need to throw exception in ctor, 
>>> because the default ctor just puts the object in a safe state (e.g. zero 
>>> the pointers, etc.) and the actual construction is done in a /ad hoc/ 
>>> construction method (e.g. Init(), Create()...).
>>>
>>> Note also that if you throw an exception in the ctor, the destructor is 
>>> *not* called! So, to write exception-safe code, you should pay attention 
>>> to this point and provide proper cleanup code in ctor as well.
>>> This is bad, IMHO.
>>> But this problem doesn't occure in two-step construction: in fact, the 
>>> default ctor doesn't throw, and if the Init()/Create() construction 
>>> method throws, the destructor is properly called.
>>>
>>> Moreover, you can't call (or is it not safe to call...) virtual methods 
>>> in a ctor; but you can call virtual methods in an Init()/Create() 
>>> method, after the default ctor put the object in a safe state.
>>>
>>> I like the two-step construction pattern for C++, and I listed above 
>>> some reasons (even if the C++-FAQ discourages its use).
>>>
>>>
>>> Giovanni
>>>
> Joseph M. Newcomer [MVP]
> email: newcomer@flounder.com
> Web: http://www.flounder.com
> MVP Tips: http://www.flounder.com/mvp_tips.htm



-- 
HLS
0
Reply Hector 6/23/2010 7:29:21 PM

"Hector Santos" <sant9442@nospam.gmail.com> wrote in message 
news:ubMkeYwELHA.4816@TK2MSFTNGP04.phx.gbl...
> That is why I say the real issue is the lack of documentation or the 
> "hidden" knowledge that are wrapped into classes.
>

BTW, you can download the source to much of the BCL (base class library) of 
..NET.  Also, you can use Reflector to get a really nice code disassembly 
(that looks so good, it looks like the original source code, except for 
things like meaningful variable names) for the rest.  So you are never 
really at the mercy of the doc.

-- David
 

0
Reply David 6/23/2010 7:33:37 PM

See below...
On Wed, 23 Jun 2010 15:58:45 -0400, Hector Santos <sant9442@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.
>
>For example, opening a file with append mode. Traditionally, the file 
>is open/creating with a FILE SHARE READ/WRITE mode.
>
>This is not the case any more with .NET.  The StreamWriter constructor:
>
>        StreamWriter(string filename, bool Append)
>
>opens the file in FileShare.Read mode only.
****
How do you append if it isn't opened in Write mode?  Did somebody perhaps misread the
specifications?  
*****
>
>Whats funny is that I asked this question in MS FORUMS and someone 
>came back suggestion that 95% scenarios this is expected usage and I 
>represent 5% scenarios.
****
100% of the people who need to append need to write to the file.  Sounds like another
"summer intern" design.
****
>
>I suggested that for C/C++ developers migrating to .NET, it would be a 
>  higher expectation that opening a file or stream in append mode is 
>atomic and Read/Write Share mode simply because that is what they are 
>use to.
>
>Anyway, my point here is that in C/C++ I don't need an exception trap 
>for fopen() based appending which I had to add in .NET to find out 
>what was going on, and after I found out and changed the code so open 
>the file first in FileShare.ReadWrite mode and pass this to 
>StreamWrite, I decided to keep the trap in to cover other possible 
>sceanario, like OUT OF DISK space :)
>
>--
>
>
>Giovanni Dicanio wrote:
>
>> On 23/06/2010 01:51, Joseph M. Newcomer wrote:
>> 
>>> Note that this could be handled as
>>>
>>> BOOL TryParse(...args...)
>>>      {
>>>       try
>>>          {
>>>           Parse(...);
>>>           return TRUE;
>>>          }
>>>      catch(..whatever..)
>>>          {
>>>           return FALSE;
>>>          }
>>> }
>>>
>>> It ain't rocket science.  And it isn't clear to me how handling the 
>>> exception results in
>>> "bad code".
>> 
>> Sure it isn't (ain't?) rocket science... but do you like a fopen that 
>> throws an exception if the file cannot be opened? No, I prefer one 
>> returning an error code.
>> The fact that you can't open a file is not an exceptional condition, and 
>> I prefer code like:
>> 
>>   if ( some_open_file_api(...) == error )
>>   {
>>      ... do what you want... (e.g. create the file, or other stuff...)
>>   }
>>   ... normal flow
>> 
>> instead of try/catch.
>> 
>> It was clearly written before: the usefulness of exceptions is inversely 
>> proportional to the number of try/catch you use: if you clutter your 
>> code with lots of try/catch then IMHO you are overusing (abusing) 
>> exceptions.
>> 
>> I think exceptions should be used in *exceptional* conditions (like 
>> David wrote before).
>> 
>> 
>> BTW: I like these articles from the OldNewThing blog:
>> 
>> "Cleaner, more elegant, and wrong"
>> http://blogs.msdn.com/b/oldnewthing/archive/2004/04/22/118161.aspx
>> 
>> "Cleaner, more elegant, and harder to recognize"
>> http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx
>> 
>> 
>> Giovanni
>> 
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Reply Joseph 6/23/2010 7:58:30 PM

David Ching wrote:

> "Hector Santos" <sant9442@nospam.gmail.com> wrote in message 
> news:ubMkeYwELHA.4816@TK2MSFTNGP04.phx.gbl...
>> That is why I say the real issue is the lack of documentation or the 
>> "hidden" knowledge that are wrapped into classes.
>>
> 
> BTW, you can download the source to much of the BCL (base class library) 
> of .NET.  Also, you can use Reflector to get a really nice code 
> disassembly (that looks so good, it looks like the original source code, 
> except for things like meaningful variable names) for the rest.  So you 
> are never really at the mercy of the doc.
> 
> -- David
> 
> 


Getting the SSCLI 2.0 was excellent - helped alot to begin 
understanding .NET base library.  Thats how I found out what FileShare 
  mode was used for the StreamWriter(string filename, bool append) 
constructor.  It also helped me with other tracings.

Didn't find one for 3.0, 3.5 or 4.0.

Is BCL the current version for 3.0 or earlier (A.D 2.0)?  If so, what 
is the URL?

Just did a search and found this thread:

http://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cbb0121-295c-4b83-b4b1-afddf4ca5257

Seeing how things are done with the SSCLI 2.0 is showing  me a lot 
about the C# and .NET framework. :)


-- 
HLS
0
Reply Hector 6/23/2010 8:02:27 PM

Joseph M. Newcomer wrote:

>> This is not the case any more with .NET.  The StreamWriter constructor:
>>
>>        StreamWriter(string filename, bool Append)
>>
>> opens the file in FileShare.Read mode only.
> ****
> How do you append if it isn't opened in Write mode?  Did somebody perhaps misread the
> specifications?  


FileShare mode for other thread/process instances. Not the current 
thread instance.

> *****
>> Whats funny is that I asked this question in MS FORUMS and someone 
>> came back suggestion that 95% scenarios this is expected usage and I 
>> represent 5% scenarios.
> ****
> 100% of the people who need to append need to write to the file.  Sounds like another
> "summer intern" design.
> ****


In lieu of something falling thru the cracks, given them the benefit 
of the doubt, either it was some buffer caching concern with the .NET 
base library or they made a security decision to force .NET developers 
to be explicit with the Share more to use.

The latter works fine so I opt to think it was a security decision, 
with some "owner" defining the share mode to be used.

-- 
HLS
0
Reply Hector 6/23/2010 8:07:08 PM

On 23/06/2010 20:57, Joseph M. Newcomer wrote:
> Good observations, all!

Thanks Joe!

Giovanni


0
Reply Giovanni 6/23/2010 9:03:24 PM

"Hector Santos" <sant9442@nospam.gmail.com> wrote in message 
news:uySKH8wELHA.1272@TK2MSFTNGP05.phx.gbl...
> Is BCL the current version for 3.0 or earlier (A.D 2.0)?  If so, what is 
> the URL?
>
> Just did a search and found this thread:
>
> http://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cbb0121-295c-4b83-b4b1-afddf4ca5257
>
> Seeing how things are done with the SSCLI 2.0 is showing  me a lot about 
> the C# and .NET framework. :)
>

Sigh, it looks like later versions aren't available.  Makes you wonder if 
they released 2.0 only to comply with Justice dept. or something!

-- David 

0
Reply David 6/23/2010 9:16:02 PM

>I used strsafe.h in VS6 for many years, and it worked quite well.
> joe

Oh yes, I installed the specific PlatformSDK Feb2003 and have
it in my includes. I used it for awhile and then unchecked the
includes and moved my original VC6 includes to the top. At the time 
I thought it might help with some include conflicts I was getting
trying some STL stuff. But I read on the net that VC6 had
problems with STL on it's own. Anyhow I plan to move on
to 2005 for any serious quests, I just still find it convenient to
experiment with stuff (except STL ) since I am so used to the
IDE.
    Thanks for the input on exceptions. I learned a little about 
when I need them or when I may not, but more importantly I
learned enough to practice how to use them. (regardless of
whether I need them or not) Before I did not have a clue as
to even how to get started on implementing them.
0
Reply RB 6/23/2010 10:02:02 PM

David Ching wrote:

> "Hector Santos" <sant9442@nospam.gmail.com> wrote in message 
> news:uySKH8wELHA.1272@TK2MSFTNGP05.phx.gbl...
>> Is BCL the current version for 3.0 or earlier (A.D 2.0)?  If so, what 
>> is the URL?
>>
>> Just did a search and found this thread:
>>
>> http://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cbb0121-295c-4b83-b4b1-afddf4ca5257 
>>
>>
>> Seeing how things are done with the SSCLI 2.0 is showing  me a lot 
>> about the C# and .NET framework. :)
>>
> 
> Sigh, it looks like later versions aren't available.  Makes you wonder 
> if they released 2.0 only to comply with Justice dept. or something!

Cross my mind too, but also done at a time where the heat was on with 
competitive OSes and .NET still was not winning a lot of people.

IMV, I think today with the Ozzie era, they are taking a chapter from 
Apple of developing a "new" fan base, lock them in and not worry about 
the older legacy customers.  Since Applet and also Google now have 
larger shares and have cracked open the door to exclusivity with no 
Anti-trust repercussion (or lack of a serious challenge because Apple 
certainly needs to get slapped), MS is licking their chops and can now 
claim they are no longer the "monopoly" per se and others are doing it 
already.  I think a prime example of this strategy and action is WP7 
where .NET is the exclusive OS for these new devices and its going to 
be centralized with a Store and all that - something that was not 
possible for MS before Apple cracked open that door for MS to enter.

-- 
HLS
0
Reply Hector 6/23/2010 10:16:53 PM

On Jun 23, 9:58=A0pm, Hector Santos <sant9...@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
>
> =A0 =A0 invalid file path, error 2
> =A0 =A0 not found, for a already exist mode, error 3
> =A0 =A0 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.
0
Reply Goran 6/24/2010 6:38:30 AM

On Jun 23, 5:39=A0pm, Hector Santos <sant9...@nospam.gmail.com> wrote:
> public bool SearchForums(string sPattern)
> {
> =A0 =A0try
> =A0 =A0{
>
> =A0 =A0 =A0Regex rgx =3D new Regex(sPattern, RegexOptions.IgnoreCase);
> =A0 =A0 =A0foreach (var forum in ForumsList)
> =A0 =A0 =A0{
> =A0 =A0 =A0 =A0MatchCollection matches =3D rgx.Matches(forum.Description)=
;
> =A0 =A0 =A0 =A0if (matches.Count > 0)
> =A0 =A0 =A0 =A0{
> =A0 =A0 =A0 =A0 =A0 =A0/// got something
> =A0 =A0 =A0 =A0}
> =A0 =A0 =A0}
> =A0 =A0 =A0return true;
> =A0 =A0}
> =A0 =A0catch (Exception ex)
> =A0 =A0{
> =A0 =A0 =A0MessageBox.Show("Regular Expression Error: " + ex.Message);
> =A0 =A0}
> =A0 =A0return 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 =E0 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.
0
Reply Goran 6/24/2010 8:06:04 AM

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...@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.

0
Reply Hector 6/24/2010 11:18:13 AM

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...@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
0
Reply Hector 6/24/2010 11:58:26 AM

On Jun 24, 1:18=A0pm, Hector Santos <sant9...@nospam.gmail.com> wrote:
> But again, you proved my point. =A0Until 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.
0
Reply Goran 6/24/2010 12:02:57 PM

On Jun 24, 1:58=A0pm, Hector Santos <sant9...@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
>
> =A0 =A0 =A0not found
> =A0 =A0 =A0bad input (bad path)
> =A0 =A0 =A0locked error
> =A0 =A0 =A0sharing error
>
> are natural errors with a high expectation, with a certain level of
> natural recovery, while others are global and not highly recovery:
>
> =A0 =A0 =A0out of memory
> =A0 =A0 =A0out of disk space
> =A0 =A0 =A0hard 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.
0
Reply Goran 6/24/2010 12:14:19 PM

Goran wrote:

> On Jun 24, 1:18 pm, Hector Santos <sant9...@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! }
> 
> ?


This is why I said, as with the simple fopen(), the most typical 
errors of "interest" are literally related to:

     not found
     bad input
     locking
     sharing

any other error is more system or hardware related.

> 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);
    }

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 generally focus contain errors at the point of functionality. I 
really use a catch all, this is more "recent" for me and only where 
required, i.e, ODBC classes.  I make extensive use of exceptions for 
our RTE for our Wildcat! BASIC p-code language, where like a .NET 
environment, you must capture programmer faults so it won't bring the 
Wildcat! Interactive NET server "OS" per se.

Even in our WCBASIC language were we offer CATCH exception trapping, 
the same issues apply, - do you use specific catch traps or catch 
alls. It depends.

For example, since our system deals with communications, WCX (compiled 
wcBASIC applets) has "Connection Drops" concepts.

If the programmer did not add any CATCH blocks, then the RTE will 
abort the WCX at the next immediate OP code, cleaning up all its 
managed resources.

But the programmer who needs graceful trapping or detection of 
connection drop can do so as well, and for a CATCH, the RTE will jump 
to that block, etc.

But the programmer can also disable the RTE connection drop detection 
and allow the applet do the detection or not at all.

The latter might be useful where it knows it will complete and needs 
no interruption regardless of a connection drop, or it can do a check 
and gracefully clean up and exit.

etc, etc, etc.


> 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!


Again, it was more of a generalization.  As I learn .NET, I will trap 
catches around usage of .NET library classes, etc, because I am not 
fully aware of all the possible issues with it.

Example, where I started with a global and then fine tune it.

For wcLex, the simple "get going" usage of a socket listener:


    try
    {
       server = new TcpListener(localAddr, port);
       server.Start();
       worker.ReportProgress(0, "- Waiting for clients");
       uint nClientTid = 0;
       while (true)
       {
         nClientTid++;
         ClientData ctcp = new ClientData(
                             server.AcceptTcpClient().Client,
                             nClientTid);
         worker.ReportProgress(1, ctcp);
        }
    }
    catch (SocketException err)
    {
      // 10004 expected for breaking socket handle
      if (err.ErrorCode != 10004)
      {
        worker.ReportProgress(0,
           String.Format("! SocketException: ErrorCode: {0}",
                           err.ErrorCode));
      }
    }
    finally
    {
      // Stop listening for new clients.
      worker.ReportProgress(0, "- Ending");
      server.Stop();
    }

The above was quick original code, and then the fine tuned to handled 
to bunch of scenarios, some which only came after KNOWING what part of 
the socket class does what.

For example, when it came to testing conflictive bindings (two 
instances of wcLEX trying to open the same address and port), the 
CATCH ALL showed the socket exception.

The question was, which call throw it?

Was it?

       server = new TcpListener(localAddr, port);

or was it?

       server.Start();

It was the latter, so a try was added around it to catch that specific 
  error event.

Since the above was part of the BackgroundWorker_DoWork event, I also 
spend time to send feedback to the calling RunWorkerAsync() to above 
the starting of the server.  Throwing exceptions in dowork did not get 
caught. I need to learn about that aspect of it.  But I used mutexes 
to signal a StartupOK event.  Here is the code, unchanged:

         private void backgroundWorkerServer_DoWork(object sender, 
DoWorkEventArgs e)
         {
             BackgroundWorker worker = sender as BackgroundWorker;
             try
             {
                 worker.ReportProgress(0, "* Starting NNTP Server");
                 server = new TcpListener(localAddr, port);
                 server.Start();
                 StartupOk = true;
                 StartupEvent.Set();
             }
             catch (SocketException err)
             {
                 if (err.SocketErrorCode == 
SocketError.AddressAlreadyInUse)
                 {
                     worker.ReportProgress(0, String.Format("! Socket 
Address/Port already in use: {0}:{1}",mySettings.IPAddress, 
mySettings.PortNumber));
                 }
                 else
                 {
                     worker.ReportProgress(0, String.Format("! Init 
SocketException: ErrorCode: {0} {1}", err.ErrorCode, 
err.SocketErrorCode));
                 }
                 StartupEvent.Set();
                 return;
             }

             try
             {
                 worker.ReportProgress(0, "- Waiting for clients");
                 uint nClientTid = 0;
                 while (true)
                 {
                     nClientTid++;
                     ClientData ctcp = new 
ClientData(server.AcceptTcpClient().Client, nClientTid, mySettings);
                     worker.ReportProgress(1, ctcp);
                 }
             }
             catch (SocketException err)
             {
                 if (err.ErrorCode != 10004)
                 {
                     worker.ReportProgress(0, String.Format("! 
SocketException: ErrorCode: {0}", err.ErrorCode));
                 }
             }
             finally
             {
                 // Stop listening for new clients.
                 worker.ReportProgress(0, "- Ending");
                 ShutDownEvent.Set();
                 server.Stop();
             }
         }

Note, the ShutDownEvent mutex was used to synchronize an EXE shutdown 
and the logging of the status becoming invalid when the application 
thread is exited and thats because I switched to using in Program.cs

    Form1 form1 = new Form1();
    Application.Run();
    GC.KeepAlive(form1);

to control the flickering of the always startup visible window made 
hidden when the notifyicon is active.

So the point is, that even when you do know how the exceptions and 
flow should be done, it can CHANGE depending on other factors.

See the thread where I talked about the LiveID SDK example Live ID DLL 
binding with the EXE no longer applies when the DLL is bound to a 
helper DLL.   There the exception logic must change.

> 
>> 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 ;-).


What IDE do you use?

-- 
HLS
0
Reply Hector 6/24/2010 12:57:58 PM

On Jun 24, 2:57=A0pm, Hector Santos <sant9...@nospam.gmail.com> wrote:
> > Of course not. For the most part, you just do
>
> > if (!myfunc(params))
> > =A0 return false;
>
> > (or equivalent thereof)
>
> Could be, sure. =A0For me, for example, logging functions:
>
> =A0 =A0 FILE *fv =3D fopen(filename, "at");
> =A0 =A0 if (fv) {
> =A0 =A0 =A0 =A0fprintf(fv,whatever);
> =A0 =A0 =A0 =A0fclose(fv);
> =A0 =A0 }

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.

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).

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".

>
> 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__.

Goran.
0
Reply Goran 6/24/2010 1:54:38 PM

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. :)

Goran,

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. :)

Again, just an example, a good template would be for boolean function:

   bool Function(<your parameters>)
   {
     try
     {
       // whatever
       return true;
     } catch (Exception ex)
       // do whats necessary or nothing.
     }
     finally
     {
       // do whats necessary or nothing
     }
     return false;
   }

but it all depends goran, what if i wanted to have an overloads too? 
What if you wanted to have available a boolean return or a exception 
model?  I have both for some functions.

 > 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;
   }

But I ended up using the latter because the parser throws string 
exception reasons, part of which also comes from the DateTime 
converter exception trap.

At the risk of getting slammed (so be nice <g>), these are the 
functions (Keep in mind that these were ported from my C/C++ NNTP 
server code, which does not have the exception version).

     public static DateTime GetNewGroupsDate(string sdt,
                                             DateTimeKind wantKind = 
DateTimeKind.Utc)
     {

         // parse parts: acceptable formats:
         // YYMMDD HHMMSS [GMT]
         // YYYYMMDD HHMMSS [GMT]

         string[] parts = sdt.Trim().Split(' ');

         if (parts.Length < 2)
         {
             throw new Exception("Insufficient parameters provided");
         }

         int len = parts[0].Length;
         if (len != 6 && len != 8)
         {
             throw new Exception("Illegal Date - [YY]YYMMDD required");
         }

         int num = Convert.ToInt32(parts[0]);
         int wYear = num / 10000; num -= wYear * 10000;
         int wMonth = num / 100; num -= wMonth * 100;
         int wDay = num;

         if (len == 6)  // support RFC3977 6/8 digits semantics
         {
             int Century = (DateTime.Now.Year / 100) * 100;
             if (wYear <= (DateTime.Now.Year - Century))
             {
                 wYear += Century;
             }
             else
             {
                 wYear += Century - 100;
             }
         }

         if (parts[1].Length != 6)
         {
             throw new Exception("Illegal time - HHMMSS required");
         }

         num = Convert.ToInt32(parts[1]);
         int wHour = num / 10000; num -= wHour * 10000;
         int wMinute = num / 100; num -= wMinute * 100;
         int wSeconds = num;

         bool gmt = false;
         if (parts.Length > 2) gmt = (parts[2].ToLower() == "gmt");

         DateTime dt = new DateTime(wYear, wMonth, wDay,
                           wHour, wMinute, wSeconds,
                           gmt ? DateTimeKind.Utc:DateTimeKind.Local);

         if (dt.Kind == DateTimeKind.Local
                && wantKind == DateTimeKind.Utc)
             return dt.ToUniversalTime();
         if (dt.Kind == DateTimeKind.Utc
                && wantKind == DateTimeKind.Local)
             return dt.ToLocalTime();
         return dt;
     }

     public static bool GetNewGroupsDate(
                             string sdt,
                             out DateTime dt,
                             DateTimeKind wantKind = DateTimeKind.Utc)
     {
         dt = DateTime.MinValue;
         try
         {
             dt = GetNewGroupsDate(sdt, wantKind);
             return true;
         }
         catch (Exception)
         {
         }
         return false;
     }



 > 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__.

While I am moving towards .NET, nothing will be release (WCLEX is a 
"get a deeper feel" of what to expect project) until the proper 
error/memory/threading framework is worked out and well understood.

Again, because .NET is richly complex and does so much for you, the 
developers need to get a handle of whats already done for you or not.
Probably the less you know the better. :) But thats not the case here.
I have language-independent expectations for well understood solid 
behavior.  Files, sockets, etc, all work one way - how its implemented 
is what needs to be understood.

What that means I must have my "managed" exceptions worked out but I 
will now under .NET, allow on "catch alls" to cover the unexpected.

The thing is under .NET you almost always have catch all at the top 
level if you use the auto-generated main program code, so that means 
that your own catch all is to keep the application running for the 
most part, and that can hurt you too.

If anything, that is the big key thing here - do you abort or 
gracefully recover for the unexpected catch alls?

This applies to any framework and language and these ideas are 100% 
application implementation specific. There are no hard rule. There are 
better rules, but never ALL cut and dry.

-- 
HLS
0
Reply Hector 6/24/2010 3:14:43 PM

On Jun 24, 5:14=A0pm, Hector Santos <sant9...@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. =A0Trust 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.

> =A0> 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. =A0The
> syntax is:
>
> =A0 =A0 =A0yymmdd hhmmss [GMT] =A0 =A0 =A0 =A0 RFC 977
> =A0 =A0 =A0[yy]yymmdd hhmmss [GMT] =A0 =A0 RFC 3977 (replaces RFC 977)
>
> I ended up with two parsing overloading functions
>
> =A0 =A0 public bool GetNNTPDateTime(string sdt, out DateTime dt)
> =A0 =A0 public DateTime GetNNTPDateTime(string sdt);
>
> so I can use the first overload:
>
> =A0 =A0public bool onNEWGROUPS(ClientData ctcp, string args)
> =A0 =A0{
> =A0 =A0 =A0 =A0DateTime dtSince;
> =A0 =A0 =A0 =A0if (!GetNNTPDateTime(args, dtSince)) {
> =A0 =A0 =A0 =A0 =A0 =A0ctcp.SendLog("501 Invalid date/time\r\n");
> =A0 =A0 =A0 =A0 =A0 =A0return true; =A0// RETURN ONLY FALSE TO BREAK CONN=
ECTION
> =A0 =A0 =A0 =A0}
> =A0 =A0 =A0 =A0....
> =A0 =A0 =A0 =A0return true;
> =A0 =A0}
>
> or I can use the exception overload version:
>
> =A0 =A0public bool onNEWGROUPS(ClientData ctcp, string args)
> =A0 =A0{
> =A0 =A0 =A0 =A0DateTime dtSince;
> =A0 =A0 =A0 =A0try
> =A0 =A0 =A0 =A0{
> =A0 =A0 =A0 =A0 =A0 =A0dtSince =3D GetNNTPDateTime(args)
> =A0 =A0 =A0 =A0}
> =A0 =A0 =A0 =A0catch (Exception ex)
> =A0 =A0 =A0 =A0{
> =A0 =A0 =A0 =A0 =A0 =A0ctcp.SendLog("501 {0}\r\n",ex.Message);
> =A0 =A0 =A0 =A0 =A0 =A0return true; =A0// RETURN ONLY FALSE TO BREAK CONN=
ECTION
> =A0 =A0 =A0 =A0}
> =A0 =A0 =A0 =A0....
> =A0 =A0 =A0 =A0return true;
> =A0 =A0}

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 =3D 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.
0
Reply Goran 6/25/2010 9:47:44 AM

Goran wrote:

> On Jun 24, 5:14 pm, Hector Santos <sant9...@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
0
Reply Hector 6/25/2010 9:54:10 PM

83 Replies
788 Views

(page loaded in 4.254 seconds)


Reply: