From: Joseph M. Newcomer on
Good observations, all!
joe
On Wed, 23 Jun 2010 17:39:12 +0200, Giovanni Dicanio
<giovanniDOTdicanio(a)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(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Hector Santos on
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
From: Joseph M. Newcomer on
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(a)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(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Joseph M. Newcomer on
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(a)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(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Joseph M. Newcomer on
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(a)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(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm