But if the object itself were "uncreated" then that wouldn't make any
odds. The object is clearly still alive, contrary to your previous
statement.
Yes, I have overlooked the posibility to establish a reference to an object,
construction of which fails. However, I have never claimed there is a need
to "uncreate" an object. All what is realliy needed is to free allocated
resources. Both in destructor, which is called by user, and in constructor,
which destroys partially created object in case of exception.
I'm perfectly happy to use try/catch where appropriate. Using try/catch
and then rethrowing is another alternative to using try/finally.
So, now we have two different ways, neither of which require using
fallthrough/"goto" in a switch/case statement. So much for it being
indispensible.
I repeat third time: the catch/finally replaces C macros. It does not
replace the jumping to entry point of code.
In C I had:
void destroy(level) {
switch(level) {
last: free(last);
res3: free(res3);
res2: free(res2);
res1: free(res1);
}
}
void destroy() {
destroy(last);
}
void create() {
CHECK(resource1 = allocate1()); rollback_label = resource1;
CHECK(resource2 = allocate2()); rollback_label = resource2;
CHECK(resource3 = allocate3()); rollback_label = resource3;
CHECK(last = allocatelast()); rollback_label = last;
}
In OOP you have:
void destroy(level) {
switch(level) {
last: free(last);
res3: free(res3);
res2: free(res2);
res1: free(res1);
}
}
void destroy() {
destroy(last);
}
void create() {
allocate1();
try {
allocate2();
try {
allocate3();
try {
allocate_last();
} catch {
destroy(label3);
throw;
}
} catch {
destroy(label2);
throw;
}
} catch {
destroy(label1);
throw;
}
If you like, you may replace the switch by simulation of code execution as
recommended in another topic branch. But you cannot replace the 'switch' by
the 'catch'.
No, IDisposable is *not* a destructor. I believe that there's some
relationship in C++/CLI between IDisposable and destructors, but in C#
(post v1) there is no such thing as a destructor. In particular, there
is nothing which will automatically be called in C# at the end of the
scope of a variable.
I call a destructor a method which is needed to be called to free allocated
resources regardless of who makes the call.
You seem to take it for granted that reducing the amount of code
improves code readability. Quite often I'll find that the most readable
form of some code is *not* the shortest.
I agree that a bitmap in jpeg form is hard to read/edit but when you have a
common pattern which is repeated 1000 times in a text of program it is not
just easier to read when the pattern is packed in reusable routine, it is
easiter to mantain for reusability reason. I'm sure the redundant approach
based on quich and durty copy-and-paste is a bad practice.
You are free to write
if ((res1 = func1()) != OK) {
log (res1);
destroy(level);
return
}
level = level1;
if ((res2 = func2()) != OK) {
log (res2);
destroy(level);
return
}
level = level2;
....
istead of
CHECK(res1 = func1, level1);
CHECK(res2 = func2, level2);
....
You can even write the multiline monsters
if (func() == true)
{
return true;
}
else
{
return false;
}
As I see everywhere and I have seen "standards" that coerses producing this,
instead of brief and clear: return func();
There is a razor principle, put by Einstain: things must be done as simple
as possible. I know that the really beautiful things are those which have
nothing redundant. Overcomplication is bad design. I beleive the programmers
are undergraduated creatures vocated to produce loads of "sw".
Compile it with the "TESTING" symbol defined, and it'll print the two
strings. Compile it without the "TESTING" symbol defined, and nothing
will be printed.
I have heard of conditional compilation. The problem is however that the
debug level can be changed on the same executable. You cannot avoid code
generation to implement lazy evaluation. The macros check the condition
before passing to the message construction code execution.