By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,652 Members | 989 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,652 IT Pros & Developers. It's quick & easy.

already used in a 'child' scope to denote something else

P: n/a
{
int i = 2;
}
int i = 1;

There is no 'i' defined in the 'parent' context from the moment of
declaration on. So what is the problem? They tell us they pursue language
simplicity. The rule "do not define a variable more than once in the same
context" is natural, and simplest therefore. All normal languages obey it
therefore. Overcomplicating a grammar by injecting more barrieres is a path
right away from simplicity. Another obstacle at the plain place introduced
in C# for no reason is blocking "fall throughs" in switch -- the feature
wich can be very useful sometimes. C# designers demonstrate some excessive
zeal on 'protecting' us from doing things naturally, going strightforward
ways.

"Give a fool rope enough and he'll hang himself."
Jun 8 '07 #1
Share this Question
Share on Google+
56 Replies


P: n/a
On Jun 8, 7:59 am, "valentin tihomirov" <V_tihomi...@best.eewrote:
{
int i = 2;
}
int i = 1;

There is no 'i' defined in the 'parent' context from the moment of
declaration on. So what is the problem?
>From section 10.7 of the spec:
<quote>
The scope of a local variable declared in a local-variable-declaration
is the block in which the declaration occurs.
</quote>

In other words, the "outer" variable i has scope which includes the
part of the block before it was declared. There's then an extra rule:

<quote>
Within the scope of a local variable, it is a compile-time error to
refer to the local variable in a textual position that precedes the
local-variable-declarator of the local variable.
</quote>

The rationale is given in notes of the spec:

<quote>
Note: The scoping rules for local variables are designed to guarantee
that the meaning of a name used in an expression context is always the
same within a block. If the scope of a local variable were to extend
only from its declaration to the end of the block, then in the example
above, the first assignment would assign to the instance variable and
the second assignment would assign to the local variable. In certain
situations but not in the exampe above, this could lead to a compile-
time error if the statements of the block were later to be rearranged.
</quote>
They tell us they pursue language
simplicity. The rule "do not define a variable more than once in the same
context" is natural, and simplest therefore. All normal languages obey it
therefore. Overcomplicating a grammar by injecting more barrieres is a path
right away from simplicity.
Another obstacle at the plain place introduced
in C# for no reason is blocking "fall throughs" in switch -- the feature
wich can be very useful sometimes.
Very useful sometimes when it's deliberate, but also very painful when
you don't want it and accidentally have it. Note that you *can* use
multiple cases for a single block, you just can't have case/code/case/
code without a break.

I suspect that when working with C, I ran into more times when I
forgot to include the break than times when I deliberately wanted to
fall through.

The switch statement isn't very nicely designed in general, however -
it harks back to C too much, IMO. I would rather have seen cases
require an extra set of braces, and for fallthrough you could then
have an explicit "continue" instead of a break for non-fallthrough.

So yes, I agree that switch isn't great - but taking away the
restriction against fallthrough would make it even worse, IMO.
C# designers demonstrate some excessive
zeal on 'protecting' us from doing things naturally, going strightforward
ways.
Well, I'm happy with both of these decisions.
"Give a fool rope enough and he'll hang himself."
True. The less rope you provide, the more foolish he has to be
though...

Jon

Jun 8 '07 #2

P: n/a
In other words, the "outer" variable i has scope which includes the
part of the block before it was declared. There's then an extra rule:
It is a fact that statements are executed seqientially, one after another.
It is truth that a block of instructions is executed as one statement. It is
truth that the variables in the imerative languages, which allow deferred
declarations, are visible only past declaration. Acquiring these basic
matters, everybody understands that the parent block variables declared past
the block are not visible inside the block and that the block internal
variables are not visible past the block. The other considerations are
irrationale.
<quote>In certain
situations but not in the exampe above, this could lead to a compile-
time error if the statements of the block were later to be rearranged.
</quote>
Rearranging code always can yeild errors. Does this argument give me power
to infer arbitrary rules?
>They tell us they pursue language
simplicity. The rule "do not define a variable more than once in the same
context" is natural, and simplest therefore. All normal languages obey it
therefore. Overcomplicating a grammar by injecting more barrieres is a
path
right away from simplicity.
>Another obstacle at the plain place introduced
in C# for no reason is blocking "fall throughs" in switch -- the feature
wich can be very useful sometimes.

Very useful sometimes when it's deliberate, but also very painful when
you don't want it and accidentally have it. Note that you *can* use
multiple cases for a single block, you just can't have case/code/case/
code without a break.

I suspect that when working with C, I ran into more times when I
forgot to include the break than times when I deliberately wanted to
fall through.

I suppose that the first thing the programmers should know is the sequence
of instruction execution. Normally, the statements are eveluated
sequentially. Should we put an explicit branch after each and every
statement to avoid the natural "fall through"? The fallthrough ban does not
save you from the infinite kinds of errors you still can make, including
wrong branching. It just infers a fair amount of code where it is
unnecessariy. You should consider avoid programming be safe. I doubt that
the requirement to pile up the loads of syntactic salt improves the quality
of code the unconscious people produce.
Jun 8 '07 #3

P: n/a
On Jun 8, 1:16 pm, "valentin tihomirov" <V_tihomi...@best.eewrote:

<snip>
Rearranging code always can yeild errors. Does this argument give me power
to infer arbitrary rules?
I was just giving you the reasons the language designers gave.
Personally, I don't have a problem with it - I find it tends to make
the code more readable to give the variables different names in this
kind of case anyway. I can't say it's bothered me that often - it's
hardly a straitjacket, is it?
I suspect that when working with C, I ran into more times when I
forgot to include the break than times when I deliberately wanted to
fall through.

I suppose that the first thing the programmers should know is the sequence
of instruction execution.
It's not a matter of knowing the rules, it's a matter of whether the
rules let you easily make mistakes.
Every time I forgot to put a break in, it was a simple matter of
forgetfulness, not a failure to understand what the code would do.

No, this won't prevent every mistake. Yes, it prevents certain ways of
working. However, I believe it helps more than it hinders, which is
why I'm in favour of it.

Regarding your change of subject line, I would retort: "Go ahead. Stop
using C#. That will stop you from being hindered by its rules."
Seriously, if you dislike so many design decisions of a language, why
use it?

Jon

Jun 8 '07 #4

P: n/a
Regarding your change of subject line, I would retort: "Go ahead. Stop
using C#. That will stop you from being hindered by its rules."
Seriously, if you dislike so many design decisions of a language, why
use it?

Jon
Why to work to satisfy all the perversive desires of the masters who kill
our planet? Yea, we are "free". We are allowed not to use English, even not
to use Windows. At this point you should suggest me to design my own
language (to talk to myself). The liberals can even mention you that you are
free not to breath if you do not like to. In other words: "If you do not
like our way of ruling the world, you are free to die". Are they serious?
Jun 8 '07 #5

P: n/a
The switch statement isn't very nicely designed in general, however -
it harks back to C too much, IMO. I would rather have seen cases
require an extra set of braces, and for fallthrough you could then
have an explicit "continue" instead of a break for non-fallthrough.
That does exist... "goto case"
Jun 8 '07 #6

P: n/a
On Jun 8, 2:51 pm, "valentin tihomirov" <V_tihomi...@best.eewrote:
Regarding your change of subject line, I would retort: "Go ahead. Stop
using C#. That will stop you from being hindered by its rules."
Seriously, if you dislike so many design decisions of a language, why
use it?

Why to work to satisfy all the perversive desires of the masters who kill
our planet? Yea, we are "free". We are allowed not to use English, even not
to use Windows. At this point you should suggest me to design my own
language (to talk to myself). The liberals can even mention you that you are
free not to breath if you do not like to. In other words: "If you do not
like our way of ruling the world, you are free to die". Are they serious?
Well, you were the one to suggest "Stop programming" to start with.

Jon

Jun 8 '07 #7

P: n/a
On Jun 8, 3:46 pm, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
The switch statement isn't very nicely designed in general, however -
it harks back to C too much, IMO. I would rather have seen cases
require an extra set of braces, and for fallthrough you could then
have an explicit "continue" instead of a break for non-fallthrough.

That does exist... "goto case"
Ah yes, of course. As you may be able to tell, I never use it
myself :)

Jon

Jun 8 '07 #8

P: n/a
Well, you were the one to suggest "Stop programming" to start with.

The only reliable way to defend yourself from network attacks is to
disconnect from the network. It is what is used to say when somebody limits
your communication (a provider blocks some TCP ports, for instance) "for
making it safer". If you wish to avoid doing errors, you should stop doing
things. Hinderances on the plain way do not defend you.

Compiler, grammar is needed to protect from doing nonsense, like assinging
date to a boolean or using unassigned variable or writing into constant
memory. It should not protect you from doing sensable things like writng
integer const to integer var or defining a not yet defined variable or
executing statements one after another.
Jun 9 '07 #9

P: n/a
valentin tihomirov wrote:
It is a fact that statements are executed seqientially, one after another.
Actually, it's not. Statements can be, and some definitely are, executed
in parallell or out of sequence, as long as the result in every relevant
aspect is the same as if they were executed in the sequence specified in
the code.
It is truth that a block of instructions is executed as one statement. It is
truth that the variables in the imerative languages, which allow deferred
declarations, are visible only past declaration.
Not really. By design the variable is visible in the entire block in the
sense that you can not declare another variable with the same name.
Acquiring these basic
matters, everybody understands that the parent block variables declared past
the block are not visible inside the block and that the block internal
variables are not visible past the block. The other considerations are
irrationale.
No, they are most definitely rational.
Rearranging code always can yeild errors. Does this argument give me power
to infer arbitrary rules?
Now you are not being irrational. The rules are not arbitrary at all.
They are definitely relevant to the situation.
>
I suppose that the first thing the programmers should know is the sequence
of instruction execution.
It's not a matter of knowing how it works, but rather having a language
that lets you easily produce stable code.
Normally, the statements are eveluated
sequentially. Should we put an explicit branch after each and every
statement to avoid the natural "fall through"? The fallthrough ban does not
save you from the infinite kinds of errors you still can make, including
wrong branching. It just infers a fair amount of code where it is
unnecessariy.
In a switch statement you are jumping into one of many code blocks, it's
not at all unreasonable that each block should end with a statement that
specifies where the execution should continue. After all, in the
majority of cases the block will end with a break anyway.

This requirement adds a bit of unnecessary code in a few cases, but a
bit of unnecessary code is very often used to keep the language
consistent and clear. The keyword if, for example, is always followed by
a parenthesis, so the parenthesis is really totally unnecessary, but you
wouldn't argue that it should be removed or even optional, would you?

--
Göran Andersson
_____
http://www.guffa.com
Jun 9 '07 #10

P: n/a
valentin tihomirov <V_*********@best.eewrote:
Well, you were the one to suggest "Stop programming" to start with.

The only reliable way to defend yourself from network attacks is to
disconnect from the network. It is what is used to say when somebody limits
your communication (a provider blocks some TCP ports, for instance) "for
making it safer". If you wish to avoid doing errors, you should stop doing
things. Hinderances on the plain way do not defend you.
Right - and likewise, the only way it seems that you'll stop being
cross about things that C# stops you from doing is to stop using C#.
Compiler, grammar is needed to protect from doing nonsense, like assinging
date to a boolean or using unassigned variable or writing into constant
memory. It should not protect you from doing sensable things like writng
integer const to integer var or defining a not yet defined variable or
executing statements one after another.
Well, I'm sure I'm not the only one who's been bitten by accidental
fallthrough in switch statements in C. As I said, I would prefer a more
radical overhaul of switch/case, but I'd rather have what we've got
than a version which has all the ugliness of the current version but
with the added problem of fallthrough.

As Ben pointed out, you can always use goto case if you really want the
effect of fallthrough.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Jun 9 '07 #11

P: n/a
>It is truth that a block of instructions is executed as one statement. It
>is truth that the variables in the imerative languages, which allow
deferred declarations, are visible only past declaration.

Not really. By design the variable is visible in the entire block in the
sense that you can not declare another variable with the same name.
>Acquiring these basic matters, everybody understands that the parent
block variables declared past the block are not visible inside the block
and that the block internal variables are not visible past the block. The
other considerations are irrationale.

No, they are most definitely rational.
>Rearranging code always can yeild errors. Does this argument give me
power to infer arbitrary rules?

Now you are not being irrational. The rules are not arbitrary at all. They
are definitely relevant to the situation.
I repeat, code rearrangement can always infer an error. One can tell that
water is wet. Thelling that something is good because of truth/tautalogy is
a bad excuse for lawmaking.
>I suppose that the first thing the programmers should know is the
sequence of instruction execution.

It's not a matter of knowing how it works, but rather having a language
that lets you easily produce stable code.
In the beginning of the post you point out the underlying processor details.
I do not see how you find and stress the details, which should normally be
hidden from programmer, as relevant and important, while disdaining the
first thing any programmer should understand -- the program flow.

>
>Normally, the statements are eveluated sequentially. Should we put an
explicit branch after each and every statement to avoid the natural "fall
through"? The fallthrough ban does not save you from the infinite kinds
of errors you still can make, including wrong branching. It just infers a
fair amount of code where it is unnecessariy.

In a switch statement you are jumping into one of many code blocks, it's
not at all unreasonable that each block should end with a statement that
specifies where the execution should continue. After all, in the majority
of cases the block will end with a break anyway.

This requirement adds a bit of unnecessary code in a few cases, but a bit
of unnecessary code is very often used to keep the language consistent and
clear. The keyword if, for example, is always followed by a parenthesis,
so the parenthesis is really totally unnecessary, but you wouldn't argue
that it should be removed or even optional, would you?
The 'switch-cases' are really a multi-option kind of 'if' statement. The
code blocks should be wrapped by braces, therefore indeed. However, the
switches are are a structural programming heritage. Morern, OOP languages
replace the code lookups by passing function pointers and, later, by object
references. So, normally, switches should be rare. The important case where
switches ARE INDISPENSABLE is jumping to a beginning of code. This is needed
when you mark a start/entry point to your code. For instance, you allocate
resourses 1, 2, 3 and roll back in case of error in reverse order 3, 2, 1 in
case of error starting at the reached stage. This is the fallthrough feature
which makes the switches indispensable. And they are nothing like 'if'
statements in this invaluable scenario. Sadliy, when this technique is
prohibited. It is especially sad when good features are abandoned in favour
of the people who do not care about program statements execution flow.
Jun 9 '07 #12

P: n/a
Right - and likewise, the only way it seems that you'll stop being
cross about things that C# stops you from doing is to stop using C#.
... and invent my own language+OS and ... if aI do not like the decisions
made by men in power.

>Compiler, grammar is needed to protect from doing nonsense, like
assinging
date to a boolean or using unassigned variable or writing into constant
memory. It should not protect you from doing sensable things like writng
integer const to integer var or defining a not yet defined variable or
executing statements one after another.

Well, I'm sure I'm not the only one who's been bitten by accidental
fallthrough in switch statements in C. As I said, I would prefer a more
radical overhaul of switch/case, but I'd rather have what we've got
than a version which has all the ugliness of the current version but
with the added problem of fallthrough.
If you were bitten for omitting a statement, it does not mean that this
statememt must be incorporated into the grammar.

As Ben pointed out, you can always use goto case if you really want the
effect of fallthrough.
Would you like to have the effect to a series of your program statements by
emulating the "fallthrough" by explicit goto after every statement? As Bob
http://www.bobcongdon.net/blog/2003/...statement.html points it
out, C# designers should introduce a "safe" must-break-switch rather than
"improving" the switch by disallowing fall-through and then adding the goto
junk.
Jun 9 '07 #13

P: n/a

"valentin tihomirov" <V_*********@best.eewrote in message
news:e$*************@TK2MSFTNGP06.phx.gbl...
>Right - and likewise, the only way it seems that you'll stop being
cross about things that C# stops you from doing is to stop using C#.

.. and invent my own language+OS and ... if aI do not like the decisions
made by men in power.

>>Compiler, grammar is needed to protect from doing nonsense, like
assinging
date to a boolean or using unassigned variable or writing into constant
memory. It should not protect you from doing sensable things like writng
integer const to integer var or defining a not yet defined variable or
executing statements one after another.

Well, I'm sure I'm not the only one who's been bitten by accidental
fallthrough in switch statements in C. As I said, I would prefer a more
radical overhaul of switch/case, but I'd rather have what we've got
than a version which has all the ugliness of the current version but
with the added problem of fallthrough.

If you were bitten for omitting a statement, it does not mean that this
statememt must be incorporated into the grammar.

>As Ben pointed out, you can always use goto case if you really want the
effect of fallthrough.

Would you like to have the effect to a series of your program statements
by emulating the "fallthrough" by explicit goto after every statement? As
Bob http://www.bobcongdon.net/blog/2003/...statement.html points
it out, C# designers should introduce a "safe" must-break-switch rather
than "improving" the switch by disallowing fall-through and then adding
the goto junk.
No, forgetting a break is a common enough error that it's not unreasonable
to require an explicit flow control statement. What's wrong with C# is that
an MVP like Jon could not know that fall-through was available with the
"goto case" construct. The error message should be written more like:

Case block ended without flow transfer, you probably wanted "break" or "goto
case" but "return", "continue" or "throw" would also work. And "continue"
should definitely not be redefined to provide fall-through, that would
really make a confusing incompatibility with C.

Jun 9 '07 #14

P: n/a
valentin tihomirov <V_*********@best.eewrote:
Right - and likewise, the only way it seems that you'll stop being
cross about things that C# stops you from doing is to stop using C#.

.. and invent my own language+OS and ... if aI do not like the decisions
made by men in power.
Yes, it's a silly idea - just like your suggestion of "Stop
programming" is, IMO. That was my point.
Well, I'm sure I'm not the only one who's been bitten by accidental
fallthrough in switch statements in C. As I said, I would prefer a more
radical overhaul of switch/case, but I'd rather have what we've got
than a version which has all the ugliness of the current version but
with the added problem of fallthrough.

If you were bitten for omitting a statement, it does not mean that this
statememt must be incorporated into the grammar.
It suggests that it wouldn't be a bad idea. I like ideas that mean I
make fewer mistakes, if they don't constrain me too much - and
disallowing fallthrough has hardly ever constrained me at all.
As Ben pointed out, you can always use goto case if you really want the
effect of fallthrough.

Would you like to have the effect to a series of your program statements by
emulating the "fallthrough" by explicit goto after every statement? As Bob
http://www.bobcongdon.net/blog/2003/...statement.html points it
out, C# designers should introduce a "safe" must-break-switch rather than
"improving" the switch by disallowing fall-through and then adding the goto
junk.
So then you really wouldn't be able to do what you want *at all*. How
is that better for you? If you don't like using the "goto" then just
don't - I know I don't.

I really don't care that much whether C# allows the use of "goto" or
not, given that I don't use it - but it seems odd to complain that the
language doesn't let you do something, and then complain that you can
do it but you don't happen to like the syntax.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Jun 9 '07 #15

P: n/a
Ben Voigt [C++ MVP] <rb*@nospam.nospamwrote:
Would you like to have the effect to a series of your program statements
by emulating the "fallthrough" by explicit goto after every statement? As
Bob http://www.bobcongdon.net/blog/2003/...statement.html points
it out, C# designers should introduce a "safe" must-break-switch rather
than "improving" the switch by disallowing fall-through and then adding
the goto junk.

No, forgetting a break is a common enough error that it's not unreasonable
to require an explicit flow control statement. What's wrong with C# is that
an MVP like Jon could not know that fall-through was available with the
"goto case" construct.
I'd say that's more of a fault with me than with the language :)

(Then again, there are various areas I don't know much about, if I try
not to use them anyway. I know very little about unsafe code, about
"goto" in general, and about any operator precedence which I wouldn't
want to assume that readers would know.)
The error message should be written more like:
Case block ended without flow transfer, you probably wanted "break" or "goto
case" but "return", "continue" or "throw" would also work.
That probably wouldn't have educated me, as I wouldn't have seen the
error often enough for it to be remembered.
And "continue" should definitely not be redefined to provide
fall-through, that would really make a confusing incompatibility with
C.
Yes, that's a fair point. How about continue with a case label? Still
too confusing? On balance, "goto" probably captures the intent
reasonably well.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Jun 9 '07 #16

P: n/a
valentin tihomirov <V_*********@best.eewrote:

<snip>
The important case where
switches ARE INDISPENSABLE is jumping to a beginning of code. This is needed
when you mark a start/entry point to your code. For instance, you allocate
resourses 1, 2, 3 and roll back in case of error in reverse order 3, 2, 1 in
case of error starting at the reached stage. This is the fallthrough feature
which makes the switches indispensable.
I've never needed to do that, despite using multiple resources. The
"finally" part of a try/finally or a try/catch/finally statement is the
C# way of handling this.
And they are nothing like 'if' statements in this invaluable
scenario. Sadliy, when this technique is prohibited. It is especially
sad when good features are abandoned in favour of the people who do
not care about program statements execution flow.
Perhaps those people have a different (and IMO better and safer) idiom
in mind, such as "finally".

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Jun 9 '07 #17

P: n/a

"Jon Skeet [C# MVP]" <sk***@pobox.comwrote in message
news:MP*********************@msnews.microsoft.com. ..
valentin tihomirov <V_*********@best.eewrote:

<snip>
>The important case where
switches ARE INDISPENSABLE is jumping to a beginning of code. This is
needed
when you mark a start/entry point to your code. For instance, you
allocate
resourses 1, 2, 3 and roll back in case of error in reverse order 3, 2, 1
in
case of error starting at the reached stage. This is the fallthrough
feature
which makes the switches indispensable.
You can get this just as easily with "goto case", or placing the switch
inside a loop, so that only one step is performed each iteration, followed
by (switch) break.

I've seen this used in environments without exception support, such as
kernel code.
>
I've never needed to do that, despite using multiple resources. The
"finally" part of a try/finally or a try/catch/finally statement is the
C# way of handling this.
C++ RAII is so far superior to try/finally it isn't funny. I learned
try/finally first, but after learning why ISO C++ doesn't have it, I much
prefer the C++ way.

C# support comes in the form of using... which is just an accident waiting
to happen when it isn't used properly.
>
>And they are nothing like 'if' statements in this invaluable
scenario. Sadliy, when this technique is prohibited. It is especially
sad when good features are abandoned in favour of the people who do
not care about program statements execution flow.

Perhaps those people have a different (and IMO better and safer) idiom
in mind, such as "finally".

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Jun 9 '07 #18

P: n/a
"Jon Skeet [C# MVP]" <sk***@pobox.comwrote in message
news:MP*********************@msnews.microsoft.com. ..
valentin tihomirov <V_*********@best.eewrote:
Right - and likewise, the only way it seems that you'll stop being
cross about things that C# stops you from doing is to stop using C#.

.. and invent my own language+OS and ... if aI do not like the decisions
made by men in power.

Yes, it's a silly idea - just like your suggestion of "Stop
programming" is, IMO. That was my point.

And what is the point if not using the language you must to use? The idea to
stop doing anything is the development of the popular idea that all possible
hinderances increase safety.

I really don't care that much whether C# allows the use of "goto" or
not, given that I don't use it - but it seems odd to complain that the
language doesn't let you do something, and then complain that you can
do it but you don't happen to like the syntax.
I always told I do not like the hinderances that protect me doing sensable
things, that "protect" me from going simply, easily, naturally,
strightforwardly, directy.
Jun 9 '07 #19

P: n/a
Perhaps those people have a different (and IMO better and safer) idiom
in mind, such as "finally".
Finally in the constructor? The constructors are ubiquitous but they must
rollback the construction in a case of error. You cannot use finally
therefore. You could use the except. But it is silly to duplicate the code,
which must be supplied in destructor. So, neither 'try' nor 'finally'
replace the seek for code entry point. They rather compliment it. I tried to
explain these considerations in my unfinished blogg
http://valjok.blogspot.com/2007/05/r...cessfully.html .
Unfortunately, C# designers abridged the technique to jump at code starting
point making this my technique ugly.

Jun 9 '07 #20

P: n/a

"valentin tihomirov" <V_*********@best.eewrote in message
news:u%****************@TK2MSFTNGP05.phx.gbl...
"Jon Skeet [C# MVP]" <sk***@pobox.comwrote in message
news:MP*********************@msnews.microsoft.com. ..
>valentin tihomirov <V_*********@best.eewrote:
>Right - and likewise, the only way it seems that you'll stop being
cross about things that C# stops you from doing is to stop using C#.

.. and invent my own language+OS and ... if aI do not like the decisions
made by men in power.

Yes, it's a silly idea - just like your suggestion of "Stop
programming" is, IMO. That was my point.


And what is the point if not using the language you must to use? The idea
to stop doing anything is the development of the popular idea that all
possible hinderances increase safety.

>I really don't care that much whether C# allows the use of "goto" or
not, given that I don't use it - but it seems odd to complain that the
language doesn't let you do something, and then complain that you can
do it but you don't happen to like the syntax.

I always told I do not like the hinderances that protect me doing sensable
things, that "protect" me from going simply, easily, naturally,
strightforwardly, directy.
<sarcasm>
C# is designed with human resources in mind, not the programmer. With C#,
you guarantee that no code contains features that your ubiquitous "person
with C# programming on their resume" can't understand. This drives down the
maximum salary which can be earned by a C# progammer, because any time the
employee asks too much, HR can just replace them.

The way C# accomplishes this is by using language restrictions to drive
everyone into the mold of writing code "the way".

Don't like it, use Perl instead, where the motto is "There's more than one
way to do it".
</sarcasm>

Jun 9 '07 #21

P: n/a
valentin tihomirov <V_*********@best.eewrote:
Yes, it's a silly idea - just like your suggestion of "Stop
programming" is, IMO. That was my point.

And what is the point if not using the language you must to use? The idea to
stop doing anything is the development of the popular idea that all possible
hinderances increase safety.
What's forcing you to use C#? Even if you're using it professionally, I
suspect there are plenty of jobs around using any *reasonably*
mainstream language these days.
I really don't care that much whether C# allows the use of "goto" or
not, given that I don't use it - but it seems odd to complain that the
language doesn't let you do something, and then complain that you can
do it but you don't happen to like the syntax.

I always told I do not like the hinderances that protect me doing sensable
things, that "protect" me from going simply, easily, naturally,
strightforwardly, directy.
I don't think adding "goto" very occasionally is really hindering you
hugely, is it? At the same time, it's protecting everyone from
*accidental* fallthrough, which as I say happens a lot more often than
deliberate fallthrough, in my experience.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Jun 9 '07 #22

P: n/a
valentin tihomirov <V_*********@best.eewrote:
Perhaps those people have a different (and IMO better and safer) idiom
in mind, such as "finally".

Finally in the constructor?
You can use finally in constructors, certainly.
The constructors are ubiquitous but they must rollback the construction
in a case of error.
Well, you can't roll back the creation of the object, but you could
certainly use finally (along with a success flag) to roll back any
resources acquired.
You cannot use finally
therefore. You could use the except. But it is silly to duplicate the code,
which must be supplied in destructor.
Who said anything about requiring a destructor? Such things don't even
exist in C# (well, from C# 2 onwards - finalizers used to be called
destructors).

I can't remember the last time I needed a finalizer - they're very
rare.
So, neither 'try' nor 'finally'
replace the seek for code entry point. They rather compliment it. I tried to
explain these considerations in my unfinished blogg
http://valjok.blogspot.com/2007/05/r...cessfully.html .
Unfortunately, C# designers abridged the technique to jump at code starting
point making this my technique ugly.
Ick - macros as well. I can't say I'm thinking "simple and natural"
here... It also doesn't seem to be addressing any problem I can
remember having.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Jun 9 '07 #23

P: n/a
Don't like it, use Perl instead, where the motto is "There's more than one
way to do it".
Firstly, I never asked for many wasy of doing everything. I asked for direct
ways from which I should not be protected. Secondly, these are designers who
chose the tools. And since the disigners are the managers they choose the
mainstream dictated by Microsoft. Peahaps, there will be a chance to check
J#, which should have a fundamental design advantage over the C feature to
pile everything into one global scope-- Java allows declaration of objects
(classes, code) in the local scope where it is used.
Jun 9 '07 #24

P: n/a
You can use finally in constructors, certainly.
Who tells the contrary?
Well, you can't roll back the creation of the object, but you could
certainly use finally (along with a success flag) to roll back any
resources acquired.
Creation is rolled back by exception. If constructor returns an exception,
the object is not created. Again, constructor is used to allocate resources.
It is nonsense to use finally to unconditionally release the resourses you
need to allocate. You do not want to use finally, therefore. To rollback the
allocated resources in the case of error, the 'catch' is used. Again,
neither 'catch' nor 'finally' replace the facility to jump to a beginning of
code.
>You cannot use finally
therefore. You could use the except. But it is silly to duplicate the
code,
which must be supplied in destructor.

Who said anything about requiring a destructor? Such things don't even
exist in C# (well, from C# 2 onwards - finalizers used to be called
destructors).

I can't remember the last time I needed a finalizer - they're very
rare.

If GC does all the deallocation for you means you do not allocate anything
besides memory. You have no need to create a destructor.
>So, neither 'try' nor 'finally'
replace the seek for code entry point. They rather compliment it. I tried
to
explain these considerations in my unfinished blogg
http://valjok.blogspot.com/2007/05/r...cessfully.html .
Unfortunately, C# designers abridged the technique to jump at code
starting
point making this my technique ugly.

Ick - macros as well. I can't say I'm thinking "simple and natural"
here... It also doesn't seem to be addressing any problem I can
remember having.
Wrapping the function invokations by macros, as I do, reduces the code
amount multiple times (increasing readability accordingly). You cannot
invoke 'return' from inside a result checking function to cancel function
execution in case of error simulating excetpion handling -- you should
generate the code. Effectively, such use of macros is C fulfills the job of
exceptions in OOP languages.
Jun 9 '07 #25

P: n/a

"valentin tihomirov" <V_*********@best.eewrote in message
news:%2****************@TK2MSFTNGP02.phx.gbl...
>
>Perhaps those people have a different (and IMO better and safer) idiom
in mind, such as "finally".

Finally in the constructor? The constructors are ubiquitous but they must
rollback the construction in a case of error. You cannot use finally
therefore. You could use the except. But it is silly to duplicate the
code, which must be supplied in destructor. So, neither 'try' nor
'finally' replace the seek for code entry point. They rather compliment
it. I tried to explain these considerations in my unfinished blogg
http://valjok.blogspot.com/2007/05/r...cessfully.html .
Unfortunately, C# designers abridged the technique to jump at code
starting point making this my technique ugly.
Your technique is far inferior to the accepted methods. As you say, it
can't work in C# (no macros among other reasons). And in C++, RAII provides
for centralized cleanup in an automatic, reusable, easy-to-follow fashon.

With C++/CLI supporting stack semantics for IDisposable objects, it is the
language of choice for deterministic destruction.

About the closest you can come with C# is:

struct Rollback : IDisposable
{
private LinkedList<IDisposableresources;
public Rollback(IDisposable first) {
resources = new LinkedList<IDisposable>;
resources.Add(first);
}
public Rollback(Rollback other)
{
resources = other.resources;
other.resources = null;
}
public void Add(IDisposable resource)
{
resources.Add(resource);
}
void IDisposable.Dispose()
{
if (resources != null) {
foreach (IDisposable resource in resources) resource.Dispose();
}
}
}

Rollback components;

// in constructor
using (Rollback rollback = new Rollback(fs = new FileStream(...))) {
fs.Open(...);
rollback.Add(ev = new Event(...));
TrackEvent(ev);

...

components = new Rollback(rollback);
}

// in Dispose method
components.Dispose();
It's not very pretty, and it's hardly automatic, but it does ensure
subobjects are properly Disposed even if an exception occurs. Of course,
all the cleanup code belongs in the subobject Dispose, so it is reusable.
You still have to remember to assign components before you return, though.

Jun 9 '07 #26

P: n/a

"valentin tihomirov" <V_*********@best.eewrote in message
news:Oj**************@TK2MSFTNGP03.phx.gbl...
>
>You can use finally in constructors, certainly.

Who tells the contrary?
>Well, you can't roll back the creation of the object, but you could
certainly use finally (along with a success flag) to roll back any
resources acquired.

Creation is rolled back by exception. If constructor returns an exception,
the object is not created. Again, constructor is used to allocate
resources.
In .NET, the object is "alive" before any user constructor code starts
running, and has the ultimate runtime type associated. This is why calls to
virtual functions go directly to the most derived type. This also means a
finalizer is called, even if an exception was thrown during construction.

It is nonsense to use finally to unconditionally release the resourses you
need to allocate. You do not want to use finally, therefore. To rollback
the allocated resources in the case of error, the 'catch' is used. Again,
neither 'catch' nor 'finally' replace the facility to jump to a beginning
of code.
>>You cannot use finally
therefore. You could use the except. But it is silly to duplicate the
code,
which must be supplied in destructor.

Who said anything about requiring a destructor? Such things don't even
exist in C# (well, from C# 2 onwards - finalizers used to be called
destructors).

I can't remember the last time I needed a finalizer - they're very
rare.


If GC does all the deallocation for you means you do not allocate anything
besides memory. You have no need to create a destructor.
>>So, neither 'try' nor 'finally'
replace the seek for code entry point. They rather compliment it. I
tried to
explain these considerations in my unfinished blogg
http://valjok.blogspot.com/2007/05/r...cessfully.html .
Unfortunately, C# designers abridged the technique to jump at code
starting
point making this my technique ugly.

Ick - macros as well. I can't say I'm thinking "simple and natural"
here... It also doesn't seem to be addressing any problem I can
remember having.

Wrapping the function invokations by macros, as I do, reduces the code
amount multiple times (increasing readability accordingly). You cannot
invoke 'return' from inside a result checking function to cancel function
execution in case of error simulating excetpion handling -- you should
generate the code. Effectively, such use of macros is C fulfills the job
of exceptions in OOP languages.
Jun 9 '07 #27

P: n/a
It's not very pretty, and it's hardly automatic, but it does ensure
subobjects are properly Disposed even if an exception occurs. Of course,
all the cleanup code belongs in the subobject Dispose, so it is reusable.
You still have to remember to assign components before you return, though.
You build a list of functions to execute. In this you approach you simulate
the code rather than execute it. I entailed the rollback as an example of
where you may need to jump to a beginning of code to execute. The code
executes till the end. The starting point may vary . The possible entry
points are marked by lables. Selecting the label by switch was a natural way
to jump to the code entry point.
Jun 9 '07 #28

P: n/a

"valentin tihomirov" <V_*********@best.eewrote in message
news:eC**************@TK2MSFTNGP05.phx.gbl...
>
>It's not very pretty, and it's hardly automatic, but it does ensure
subobjects are properly Disposed even if an exception occurs. Of course,
all the cleanup code belongs in the subobject Dispose, so it is reusable.
You still have to remember to assign components before you return,
though.

You build a list of functions to execute. In this you approach you
simulate
I'm afraid it's not even that efficient. It's a list of interfaces, each of
which contains the function pointer, so there's an extra level of
indirection. The JIT has no opportunity to inline or anything. That's why
C++ automatic destruction of member objects and objects with local scope is
so far superior.
the code rather than execute it. I entailed the rollback as an example of
where you may need to jump to a beginning of code to execute. The code
executes till the end. The starting point may vary . The possible entry
points are marked by lables. Selecting the label by switch was a natural
way to jump to the code entry point.
switch-controlled construction and destruction are perfectly valid in C and
some C++ environments which don't support exceptions. C# has exceptions
though, and your method looks incompatible with exceptions, even if it
didn't suffer from so many other problems.

Jun 9 '07 #29

P: n/a
valentin tihomirov <V_*********@best.eewrote:
Well, you can't roll back the creation of the object, but you could
certainly use finally (along with a success flag) to roll back any
resources acquired.

Creation is rolled back by exception. If constructor returns an exception,
the object is not created.
That's simply not true. In most cases the created object is then
eligible for garbage collection, but that's not necessarily the case.
Indeed, it can't be, because the constructor could have assigned
"this" to a static variable. Consider the following program:

using System;

class Test
{
int i;

static Test foo;

Test()
{
i = 10;
foo = this;
throw new Exception();
}

static void Main()
{
try
{
new Test();
}
catch {}
Console.WriteLine (foo.i);
}
}

Please explain how the above code prints "10" if object creation is
rolled back when a constructor throws an exception.
Again, constructor is used to allocate resources.
It is nonsense to use finally to unconditionally release the resourses you
need to allocate.
Hence "along with a success flag".
You do not want to use finally, therefore.
No, you don't want to use a finally and rollback *unconditionally*.
Just keep a single boolean flag to say whether or not the whole
operation succeeded, and make each finally block check it. Simple.
I can't remember the last time I needed a finalizer - they're very
rare.

If GC does all the deallocation for you means you do not allocate anything
besides memory. You have no need to create a destructor.
I use plenty of non-memory resources, but don't rely on the GC to
release them - I use the IDisposable pattern.
Ick - macros as well. I can't say I'm thinking "simple and natural"
here... It also doesn't seem to be addressing any problem I can
remember having.

Wrapping the function invokations by macros, as I do, reduces the code
amount multiple times (increasing readability accordingly). You cannot
invoke 'return' from inside a result checking function to cancel function
execution in case of error simulating excetpion handling -- you should
generate the code. Effectively, such use of macros is C fulfills the job of
exceptions in OOP languages.
The use of macros has made life incredibly painful for millions of
developers, which is why macros don't tend to be in modern languages.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Jun 9 '07 #30

P: n/a
Please explain how the above code prints "10" if object creation is
rolled back when a constructor throws an exception.
Because you do not roll back the assignment.

>Again, constructor is used to allocate resources.
It is nonsense to use finally to unconditionally release the resourses
you
need to allocate.

Hence "along with a success flag".
>You do not want to use finally, therefore.

No, you don't want to use a finally and rollback *unconditionally*.
Just keep a single boolean flag to say whether or not the whole
operation succeeded, and make each finally block check it. Simple.
Peahaps, the try-catch is in your list of discouraged constructrions along
with goto. That is why you prefer finally with a flag instead of the
construct, which intentionally intorduced to take action in case of error.
I can't remember the last time I needed a finalizer - they're very
rare.

If GC does all the deallocation for you means you do not allocate
anything
besides memory. You have no need to create a destructor.

I use plenty of non-memory resources, but don't rely on the GC to
release them - I use the IDisposable pattern.
Which is a destructor. I told nothing about a need to use finalizers.

The use of macros has made life incredibly painful for millions of
developers, which is why macros don't tend to be in modern languages.
Improperly, unconsciously applied hammer can be even more painful and
dangerous. Macros are code generators. Using them greatly reduces amount of
code (program redability). The alternative of not using them in C is loads
of code. You can live without them in OOP languages because we have
exceptions supported at language level. Nevertheless, occasionally, the lack
of macros is observed. For instance, in logging
public void log (int severity, str message) {
if (severity >= debug_level)
print(message);
}

you have a lot of log function invocations. If the debug level is high
(normally, you log only errors), the function will do nothing. According to
Log4j project, the most logging time is spent on constructing the text
message. So, you construct a message to discard it. And the function is
public, so it cannot be inlined. In Delphi, which lacks ternary operators, I
also felt the lack of macros to implemement it. However in C, avoiding
macros is huge waste of labour and storage resourses.
Jun 10 '07 #31

P: n/a
valentin tihomirov <V_*********@best.eewrote:
Please explain how the above code prints "10" if object creation is
rolled back when a constructor throws an exception.

Because you do not roll back the assignment.
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.
No, you don't want to use a finally and rollback *unconditionally*.
Just keep a single boolean flag to say whether or not the whole
operation succeeded, and make each finally block check it. Simple.

Peahaps, the try-catch is in your list of discouraged constructrions along
with goto. That is why you prefer finally with a flag instead of the
construct, which intentionally intorduced to take action in case of error.
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 use plenty of non-memory resources, but don't rely on the GC to
release them - I use the IDisposable pattern.

Which is a destructor. I told nothing about a need to use finalizers.
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.
The use of macros has made life incredibly painful for millions of
developers, which is why macros don't tend to be in modern languages.

Improperly, unconsciously applied hammer can be even more painful and
dangerous. Macros are code generators. Using them greatly reduces amount of
code (program redability).
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.
The alternative of not using them in C is loads
of code. You can live without them in OOP languages because we have
exceptions supported at language level. Nevertheless, occasionally, the lack
of macros is observed. For instance, in logging
public void log (int severity, str message) {
if (severity >= debug_level)
print(message);
}

you have a lot of log function invocations. If the debug level is high
(normally, you log only errors), the function will do nothing. According to
Log4j project, the most logging time is spent on constructing the text
message. So, you construct a message to discard it. And the function is
public, so it cannot be inlined. In Delphi, which lacks ternary operators, I
also felt the lack of macros to implemement it. However in C, avoiding
macros is huge waste of labour and storage resourses.
Perhaps you haven't seen the Conditional attribute.

using System;
using System.Diagnostics;

class Test
{
static void Main()
{
PrintMe(ConstructMessage());
}

static string ConstructMessage()
{
Console.WriteLine ("Constructing message");
return "This could have taken a long time to build.";
}

[Conditional("TESTING")]
static void PrintMe(string message)
{
Console.WriteLine(message);
}
}

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.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Jun 10 '07 #32

P: n/a
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.
Jun 10 '07 #33

P: n/a
1. He went to home.
2. A gived individual of man sex consciously performed a process of foot
transportation with normal speed in past time towards an object, which
represents a place of permanent resedence of given subject.
Jun 10 '07 #34

P: n/a
valentin tihomirov wrote:
[...]
I repeat third time: the catch/finally replaces C macros. It does not
replace the jumping to entry point of code.
IMHO C macros are what they are, a simple pattern / instruction replaced
by the preprocessor. As a C++ programmer I can only say macros are evil
(in C++), since they have effects on other source code and are the main
reason why C++ is so slow. Doesn't apply to C directly, however.
>
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;
}
Why not: (Sorry for errors, I'm used more to C++ than C) ?

void* p1 = 0;
void* p2 = 0;
void* p3 = 0;

void destroy()
{
free(p1);
free(p2);
free(p3);
}

bool Alloc(void** p, char* error);
bool create()
{
if (!Alloc(p1), "ALLOC 1") return false;
if (!Alloc(p2), "ALLOC 2") return false;
if (!Alloc(p3), "ALLOC 3") return false;
return true;
}

bool Alloc(void** p, char* error)
{
if (..... error ....)
{
printf("ERROR ALLOCATING: %s\r\n", error);
return false;
}
*p = malloc(100);
return true;
}

Also readable - IMHO, without using macros. Same applies to C#.

[...]
I call a destructor a method which is needed to be called to free allocated
resources regardless of who makes the call.
In C++ there is RAII, which IMHO is the best solution. In C# we have try
/ finally or the using statement.
[...]
You can even write the multiline monsters
if (func() == true)
{
return true;
}
else
{
return false;
}

You could also simply write:

return func();

or:

return DoSomethingOnTrueOrFalse(func());

Or since commonly in this case exceptions are used:

func1();
func2();
func3();

And the error is handled somewhere outside the function block.

As I see everywhere and I have seen "standards" that coerses producing this,
instead of brief and clear: return func();
Only if IMHO you are trying to map one coding style of a language to
another. Sometimes you can't simply map your coding style to another
language, and yes sometimes it's somewhat more complex to express the
same in another language.
[...]
Andre
Jun 10 '07 #35

P: n/a
>I repeat third time: the catch/finally replaces C macros. It does not
>replace the jumping to entry point of code.

IMHO C macros are what they are, a simple pattern / instruction replaced
by the preprocessor. As a C++ programmer I can only say macros are evil
(in C++), since they have effects on other source code and are the main
reason why C++ is so slow. Doesn't apply to C directly, however.
Text including is really evelish heretage of asm. It not only makes
compilation slow -- it makes the compiler reports . However, the code
generators are there for a reason. You are free to copy and paste yourself
to "speed up your compilation times".
Also readable - IMHO, without using macros. Same applies to C#.
It is not surprising -- in case of error, you leave resources unreleased.
Furthermore, your allocate prints the message. It is ad-hoc created for your
application. Meantime, "allocating resources" normally means calling system
routine. Moreover, you omit that the macros can check return codes not only
in allocating functions, but also in using the resources:

if (!WriteFile(data1)) {
log(last error writing 1)
return;
}

if (!WriteFile(data1)) {
log(last error writing 2)
return;
}
...

The pattern is obvious and calls for reduction:
WIN32_CHECK(WriteFile(data1), "writing 1");
WIN32_CHECK(WriteFile(data2), "writing 2");
>[...]
I call a destructor a method which is needed to be called to free
allocated resources regardless of who makes the call.

In C++ there is RAII, which IMHO is the best solution. In C# we have try /
finally or the using statement.
RAII is the feature allocating resources in the stack? The object you
construct will be destroyed automatically right after the constructor
completes. Happy constructing.
func1();
func2();
func3();

And the error is handled somewhere outside the function block.
Exceptions are not panacea. They do not aholish the normal function return
values. The example was intended to demonstrate "concise vs. inflated"
writing style.

>As I see everywhere and I have seen "standards" that coerses producing
this, instead of brief and clear: return func();

Only if IMHO you are trying to map one coding style of a language to
another. Sometimes you can't simply map your coding style to another
language, and yes sometimes it's somewhat more complex to express the same
in another language.
There is nothing about style mapping. There are guidelines of a company. One
of them is we do not use ternary operators. Instead of
func(cond ? a : b, cond2 ? x : y)
we write
if (cond)
{
if (cond2)
{
func(a, x);
}
else
{
func(a, y);
}
}
else
{
if (cond2)
{
func(b, x);
}
else
{
func(b, y);
}
}

This is a perverse, redundant and thus moderen art.
Jun 10 '07 #36

P: n/a
valentin tihomirov <V_*********@best.eewrote:
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.
Again, there's no such term as "destructor" in C#, but yes - the
constructor should clear up all resources if an exception is thrown
during construction. My point was just that the object itself is *not*
automatically "deleted" immediately.
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.
Okay - so in the rare situation where I actually have more than one
resource I need to dispose of (heck, it's rare enough that my objects
have member state with *any* disposable resources) I would almost
always be able to tell whether or not the resource had been allocated
using "null". I can't immediately think of a situation where I wouldn't
be able to tell from the state itself whether or not I needed to
release that state.

At that point, it's very easy to write code which does a check-then-
release, check-then-release etc. It's also reasonably easy to make that
exception safe.

As I say though - this is incredibly rare for me.

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.
Then you're reusing existing and quite specific terminology to cover
similar situations which aren't exactly the same. That's just a recipe
for miscommunication.
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
<snip straw man>

Hey, I can come up with straw men too: you like short code? Better use
single letter variables everywhere and have all your code on one line,
right?

No, of course not.

There are times when the shortest code is the most readable. There are
plenty of times when it isn't.

Macros can introduce subtle bugs very easily, as well as often being a
nightmare to debug. I for one am glad that C# doesn't have them.
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".
So you don't believe there's any situation where longer code can be
more readable than shorter code? We'll have to agree to disagree on
that one.

Here's an example: I don't want everyone who ever reads my code to have
to know all of the operator precedence of C#. I'll assume they know
that * binds tighter than + and basics like that, but nothing *very*
complicated - so if there's anything which might introduce confusion in
a reader's mind, I'll put brackets in to make it explicit.

Those brackets are redundant, in that the compiler certainly doesn't
need them - but they help readability.
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.
I don't understand what you want to be able to do which I didn't just
demonstrate in the example. In my example the message construcvtion
code was not executed - isn't that exactly what you wanted?

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Jun 10 '07 #37

P: n/a
valentin tihomirov <V_*********@best.eewrote:
1. He went to home.
2. A gived individual of man sex consciously performed a process of foot
transportation with normal speed in past time towards an object, which
represents a place of permanent resedence of given subject.
On the other hand:

Eschew obfuscation.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Jun 10 '07 #38

P: n/a
valentin tihomirov wrote:
>>I repeat third time: the catch/finally replaces C macros. It does not
replace the jumping to entry point of code.
IMHO C macros are what they are, a simple pattern / instruction replaced
by the preprocessor. As a C++ programmer I can only say macros are evil
(in C++), since they have effects on other source code and are the main
reason why C++ is so slow. Doesn't apply to C directly, however.

Text including is really evelish heretage of asm. It not only makes
compilation slow -- it makes the compiler reports . However, the code
Yes, but macros are often misused. If you look at some code

MyMacro(Function, "some text")

you won't know how this code will expand. If it would be a function one
would know that "Function" and "some text" are arguments.
Also if you are debugging you will see only the macro, not the expanded
code.

Also for most of external or internal IDE tools it's hard to parse (C
style) macros.
generators are there for a reason. You are free to copy and paste yourself
to "speed up your compilation times".
In C macros may be O.K. In C++ the compiler is forced to compile every
header file again and again, only because a macro could be redefined and
expand completely to different code. This has nothing to do with copy /
paste
>
>Also readable - IMHO, without using macros. Same applies to C#.

It is not surprising -- in case of error, you leave resources unreleased.
Don't think so why should resources be unreleased ?
Furthermore, your allocate prints the message. It is ad-hoc created for your
application. Meantime, "allocating resources" normally means calling system
routine. Moreover, you omit that the macros can check return codes not only
in allocating functions, but also in using the resources:

if (!WriteFile(data1)) {
log(last error writing 1)
return;
}

if (!WriteFile(data1)) {
log(last error writing 2)
return;
}
...

The pattern is obvious and calls for reduction:
WIN32_CHECK(WriteFile(data1), "writing 1");
WIN32_CHECK(WriteFile(data2), "writing 2");
Yes, but what about a function: (in C)

void WIN32_CHECK(HRESULT value, char* log)
{
if (value != S_OK) ....
}

The code would be the same. The only difference would be that the macro
may expand to different code in release / debug versions. Which is
addressed in C# by conditional compilation, which IMHO is better, since
you can ship your application as both - debug and release in a single
executable.
[...]
RAII is the feature allocating resources in the stack? The object you
construct will be destroyed automatically right after the constructor
completes. Happy constructing.
Not only. It means (abstractly) that allocations and deallocations are
done in the destructor automatically.
If you embed objects in C++ in another object, they are destroyed too if
the parent object is destroyed.

You simply don't have to care about allocation / deallocation !!!

Exceptions are not panacea. They do not aholish the normal function return
values. The example was intended to demonstrate "concise vs. inflated"
writing style.

Yes. Exceptions cannot replace and shouldn't replace function return
values.
[...]
There is nothing about style mapping. There are guidelines of a company. One
of them is we do not use ternary operators. Instead of
func(cond ? a : b, cond2 ? x : y)
we write
if (cond)
{
if (cond2)
{
func(a, x);
}
else
{
func(a, y);
}

[....]
This is a perverse, redundant and thus moderen art.
It's not modern, but IMHO perhaps too much expanded.

The code above could be rewritten for example:

int v1, v2;
if (cond) v1 = a; else v1 = b;
if (cond2) v2 = x; else v2 = y;
func(v1, v2);

Andre
Jun 10 '07 #39

P: n/a
In C macros may be O.K. In C++ the compiler is forced to compile every
header file again and again, only because a macro could be redefined and
expand completely to different code. This has nothing to do with copy /
paste
If you do not want the compiler to unwind the macros generating C code, you
can avoid using macros and generate the code by your hands.
>>Also readable - IMHO, without using macros. Same applies to C#.

It is not surprising -- in case of error, you leave resources unreleased.

Don't think so why should resources be unreleased ?
They should not be unreleased. They must be released. And in your example
you forget todo so leaving them allocated (leaked).
Yes, but what about a function: (in C)

void WIN32_CHECK(HRESULT value, char* log)
{
if (value != S_OK) ....
}
The code would be the same. The only difference would be that the macro
may expand to different code in release / debug versions. Which is
addressed in C# by conditional compilation, which IMHO is better, since
you can ship your application as both - debug and release in a single
executable.
Don't you understand that you need to exit the function in case of error.
And this is the function which invokes the checking routine rather than the
checking routine. You cannot raise an exception in C/C++ in the ellipsys.

>[...]
RAII is the feature allocating resources in the stack? The object you
construct will be destroyed automatically right after the constructor
completes. Happy constructing.

Not only. It means (abstractly) that allocations and deallocations are
done in the destructor automatically.
If you embed objects in C++ in another object, they are destroyed too if
the parent object is destroyed.

You simply don't have to care about allocation / deallocation !!!
Abstragating from reality we can speak about anything. But the issue was
rolling back resourses in constructors in case of errors. The pattern

resourse = allocate();
try {
use(resourse);
} finally {
free(resourse);
}

where allocation and deallocation occurs in one routine is not applicable.

>[...]
There is nothing about style mapping. There are guidelines of a company.
One of them is we do not use ternary operators. Instead of
func(cond ? a : b, cond2 ? x : y)
we write
if (cond)
{
if (cond2)
{
func(a, x);
}
else
{
func(a, y);
}
[....]
This is a perverse, redundant and thus moderen art.

It's not modern, but IMHO perhaps too much expanded.

The code above could be rewritten for example:

int v1, v2;
if (cond) v1 = a; else v1 = b;
if (cond2) v2 = x; else v2 = y;
func(v1, v2);
You have omited the braces -- one per line -- the authority demands :) The
important thing is that the code pile upers do not understand that the
ternary operator means you want to assign one or another value depending on
a codition. When you write the redundant code: "if (cond) v1 = a; else v1 =
b;" (variable to be assigned is specified twice), you may run into
inconsistency: "v1 = a; else v2 = b;". If you give a user a button telling
"never push it", they will one day. I suspect that the ternary op expands to
if-then-else at machine code level. However, the good design does not
exhibit any redundant parts.
Jun 10 '07 #40

P: n/a
At that point, it's very easy to write code which does a check-then-
release, check-then-release etc. It's also reasonably easy to make that
exception safe.
If it is so simple to check everything, why then we need to introduce the
exceptions? BTW, check requires extracoding as well as extra processing
power, etc. And you forget that every variable in this approach must be
initialized prior to the checking (and release) .

The answer is we have the exceptions because preparatory work, which adds a
small level of complexity, reduces the automatable work greatly afterwards.

>I call a destructor a method which is needed to be called to free
allocated
resources regardless of who makes the call.

Then you're reusing existing and quite specific terminology to cover
similar situations which aren't exactly the same. That's just a recipe
for miscommunication.
I do not know if the definition of (de-/con-) structor I gave can be more
general. Especially, in the light of C# does not have destructors, as you
mention.

<snip straw man>

Hey, I can come up with straw men too: you like short code? Better use
single letter variables everywhere and have all your code on one line,
right?

No, of course not.

There are times when the shortest code is the most readable. There are
plenty of times when it isn't.
OK, your writing left me under impression that you do not agree with my
examples. Yet, I insist that the real truth, beauty is reaching the goal by
minimal effort. So it is more likely that you should collapse and remove
unnnecessary parst to optimize your expression than moving in contrary
direction.


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

So you don't believe there's any situation where longer code can be
more readable than shorter code? We'll have to agree to disagree on
that one.
Here's an example: I don't want everyone who ever reads my code to have
to know all of the operator precedence of C#. I'll assume they know
that * binds tighter than + and basics like that, but nothing *very*
complicated - so if there's anything which might introduce confusion in
a reader's mind, I'll put brackets in to make it explicit.

Those brackets are redundant, in that the compiler certainly doesn't
need them - but they help readability.
Do you want to say that calling you J instead of Jon Skeet makes your name
less redundant?

At math classes we were taught to optimize -- that is reduce the number of
operations. For instance, we were required to write 1 instead of 2/2. Later,
we introduced f'(x) to designate the lim(df(x)/dx, dx -0) when this
pattern became ubiquitous. Variable name length was not an issue. Yet, I
still often use 't' for time local variables. At object scope I tend to use
a bit more mnemonic names for the parts of the model I build.

Parenthis really add clarity, since operator precedence is not always
evident and is arbitrary sometimes. To resolve the ambiguity, the parensis
are often enforced by compiler, therefore. But in my examples there was no
ambituity as there is none in ternary operator.

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.

I don't understand what you want to be able to do which I didn't just
demonstrate in the example. In my example the message construcvtion
code was not executed - isn't that exactly what you wanted?
The strong man's position is to create multiple executables -- an executable
per macro option. When he will have two independent macros the number of
executables will be m x n. As additional benefit to maintaining multiple
distributions, he precludes himself from dynamically adjusting the macro
options (debug_level). The man is strong because of his preconception -- he
is confident that conventional routines (invocable functions) plus some
attributes can do the job of macros. No, they cannot. Code generators can do
the things which are beyound the code itself. Lazy evaluation is one of
them. Returning from routine by macro is another.
Jun 10 '07 #41

P: n/a
valentin tihomirov wrote:
[...]
If you do not want the compiler to unwind the macros generating C code, you
can avoid using macros and generate the code by your hands.
The problem is the compiler / standard has to support macros (which
affect multiple files). So to be compliant they cannot be simply removed
and in C++ commonly some proprietary workarounds like precompiled header
files are used.
[...]
They should not be unreleased. They must be released. And in your example
you forget todo so leaving them allocated (leaked).
To make the example more complete:

Instead:

CHECK(resource1 = allocate1())
CHECK(resource2 = allocate2())
CHECK(resource3 = allocate1())

in my example you would write:

if (!create()) destroy();

or assuming that exceptions are thrown:

try { create(); } catch(System.Exception e) { destroy(); }
>Yes, but what about a function: (in C)

void WIN32_CHECK(HRESULT value, char* log)
{
if (value != S_OK) ....
}
The code would be the same. The only difference would be that the macro
may expand to different code in release / debug versions. Which is
addressed in C# by conditional compilation, which IMHO is better, since
you can ship your application as both - debug and release in a single
executable.

Don't you understand that you need to exit the function in case of error.
Where is the difference if a macro returns an error or throws an
exception or a function ?

Your macro will only reduce code like:

if (!WIN32_CHECK(value, "log function")) return false;
if (!WIN32_CHECK(value, "log function")) return false;
if (!WIN32_CHECK(value, "log function")) return false;

to (Macros used):

WIN32_CHECK(value, "log function");
WIN32_CHECK(value, "log function");
WIN32_CHECK(value, "log function");

The problem is - if you read the code you can't see what the macro is
doing. How do I know if it leaves the function ?
In C++ I won't care (normally - but there are exceptions too), in C and
C# I have to care. Therefore it's IMHO not an good idea to write macros,
which simply are leaving a function.

For this kind of error handling IMHO exceptions have to be used.

The big problem IMHO in C# and C is that a programmer has to care about
exceptions too much, if a locally allocated object uses resources.
Meaning that you have to call Dispose manually.
Fortunately there is

using (....) {}

in C# which at least helps for local function scope.

And this is the function which invokes the checking routine rather than the
checking routine. You cannot raise an exception in C/C++ in the ellipsys.
Why not ? And in C++ you don't have to care if an exception is raised.
The compiler calls destructors automatically. In C# you don't have to
care only about objects holding resources (file handles, etc.).
In C you have to care about everything.

>>[...]

Abstragating from reality we can speak about anything. But the issue was
rolling back resourses in constructors in case of errors. The pattern
Sorry my newsreader has cut down the whole thread. Hmpf, not the first
time of my open source reader doing this.

In C++ resources are also freed if an exception is thrown in an objects
constructor. Though I wouldn't do this anyways. Neither in C# nor in any
other program language. Just because of the problems we are discussing
about.
resourse = allocate();
try {
use(resourse);
} finally {
free(resourse);
}

where allocation and deallocation occurs in one routine is not applicable.
I have simply matched your macros with functions using a simple boolean
instruction or null as default value for my objects.

You claimed that in OOP you have to write:

##[start of quote]
void create() {
allocate1();
try {
allocate2();
try {
allocate3();
try {
allocate_last();
} catch {
destroy(label3);
throw;
}
} catch {
destroy(label2);
throw;
}
} catch {
destroy(label1);
throw;
}

"
##[end of quote]

I just claimed that you can do it:

Object o1 = null;
Object o2 = null;

try
{
.....
}
catch(System.Exception)
{
o1.Dispose(); // destroy - meaning freeing resources
o2.Dispose(); //
}

But commonly in C# you don't have to care about, if the objects don't
hold any resources which immediately have to be freed.

>>[...]
There is nothing about style mapping. There are guidelines of a company.
One of them is we do not use ternary operators. Instead of
func(cond ? a : b, cond2 ? x : y)
we write
if (cond)
{
if (cond2)
{
func(a, x);
}
else
{
func(a, y);
}
[....]
This is a perverse, redundant and thus moderen art.
It's not modern, but IMHO perhaps too much expanded.

The code above could be rewritten for example:

int v1, v2;
if (cond) v1 = a; else v1 = b;
if (cond2) v2 = x; else v2 = y;
func(v1, v2);

You have omited the braces -- one per line -- the authority demands :) The
It should only prevent the multiple if then else clauses. Which IMHO
aren't more readable than the ternary operator.
important thing is that the code pile upers do not understand that the
ternary operator means you want to assign one or another value depending on
a codition. When you write the redundant code: "if (cond) v1 = a; else v1 =
b;" (variable to be assigned is specified twice), you may run into
inconsistency: "v1 = a; else v2 = b;". If you give a user a button telling
"never push it", they will one day. I suspect that the ternary op expands to
if-then-else at machine code level. However, the good design does not
exhibit any redundant parts.
I think rather the ternary operator would not directly match to
if-then-else but rather to a helper function:

func(Select(cond, a, b), Select(cond, x, y));

int Select(bool condition, int a, b)
{
if (condition) return a;
return b;
}
But when your authority demands it to expand to if - then - else, it may
be so. We could continue the discussion but that won't help you changing
the mind of your authority ? ;-/

Andre
Jun 11 '07 #42

P: n/a
valentin tihomirov <V_*********@best.eewrote:
At that point, it's very easy to write code which does a check-then-
release, check-then-release etc. It's also reasonably easy to make that
exception safe.

If it is so simple to check everything, why then we need to introduce the
exceptions?
This is a relatively rare case - and we're not checking for success at
the point of allocation, we're checking for earlier success at the
point of release.
BTW, check requires extracoding as well as extra processing
power, etc.
I don't think a check for nullity is going to tax the processor much,
do you?
And you forget that every variable in this approach must be
initialized prior to the checking (and release) .
Member variables are automatically initialised with null/0/etc.
The answer is we have the exceptions because preparatory work, which adds a
small level of complexity, reduces the automatable work greatly afterwards.
And nothing I've written goes against that.
Then you're reusing existing and quite specific terminology to cover
similar situations which aren't exactly the same. That's just a recipe
for miscommunication.

I do not know if the definition of (de-/con-) structor I gave can be more
general. Especially, in the light of C# does not have destructors, as you
mention.
It certainly doesn't - and neither does the CLI specification. Claiming
that either of them *do* have destructors has been a cause of confusion
for those who then expect C++ destructor semantics (where the
destructor is automatically called).
<snip straw man>

Hey, I can come up with straw men too: you like short code? Better use
single letter variables everywhere and have all your code on one line,
right?

No, of course not.

There are times when the shortest code is the most readable. There are
plenty of times when it isn't.

OK, your writing left me under impression that you do not agree with my
examples.
No, it's just that you gave extreme examples. Brevity is *often* good,
but not *always*. You can't prove that it's *always* good by giving
examples of where it's good.
Yet, I insist that the real truth, beauty is reaching the goal by
minimal effort. So it is more likely that you should collapse and remove
unnnecessary parst to optimize your expression than moving in contrary
direction.
And yet in another post you claimed that you *had* to have braces -
even though they're unnecessary as far as the compiler is concerned.
Those brackets are redundant, in that the compiler certainly doesn't
need them - but they help readability.

Do you want to say that calling you J instead of Jon Skeet makes your name
less redundant?
I have no idea what you even mean by that.
At math classes we were taught to optimize -- that is reduce the number of
operations. For instance, we were required to write 1 instead of 2/2. Later,
we introduced f'(x) to designate the lim(df(x)/dx, dx -0) when this
pattern became ubiquitous. Variable name length was not an issue. Yet, I
still often use 't' for time local variables. At object scope I tend to use
a bit more mnemonic names for the parts of the model I build.

Parenthis really add clarity, since operator precedence is not always
evident and is arbitrary sometimes. To resolve the ambiguity, the parensis
are often enforced by compiler, therefore.
And often they're *not* enforced by the compiler but still add clarity.
That's my point.
But in my examples there was no
ambituity as there is none in ternary operator.
But the point is still that there are plenty of cases where shorter
code isn't always more readable code.

The conditional operator (which is the proper name for it, by the way -
it's *a* ternary operator, in the same way that + is a binary operator,
but its name is the conditional operator) is actually a good example of
where brevity *can* be counterproductive. There are times when I've
written something with both the conditional operator and the if/else
syntax, and found the latter to be more readable. This tends to be the
case if the expressions are complicated. In simpler cases, the
conditional operator is more readable.
I don't understand what you want to be able to do which I didn't just
demonstrate in the example. In my example the message construcvtion
code was not executed - isn't that exactly what you wanted?

The strong man's position is to create multiple executables -- an executable
per macro option. When he will have two independent macros the number of
executables will be m x n. As additional benefit to maintaining multiple
distributions, he precludes himself from dynamically adjusting the macro
options (debug_level).
So you test in the code instead. Yes, there's a *tiny* amount of
redundancy - but I believe that extra effort is well worth the benefit
of not having to deal with macros.

Another alternative would be to specify a delegate which returned the
string to log - in the case where logging was turned off, you just
wouldn't execute the delegate.

I've worked with code which uses a lot of macros. I've worked with code
which conditionally logs based on simple code. The latter has been
significantly easier to understand and maintain.
The man is strong because of his preconception -- he
is confident that conventional routines (invocable functions) plus some
attributes can do the job of macros. No, they cannot. Code generators can do
the things which are beyound the code itself. Lazy evaluation is one of
them. Returning from routine by macro is another.
Macros can certainly do things which the conditional attribute can't -
but I was addressing your example of where you felt macros were
necessary. I've shown that the conditional attribute can address a lot
of that, and if you want runtime loglevel adjustment, it's far from
difficult.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Jun 11 '07 #43

P: n/a

"Andre Kaufmann" <an*********************@t-online.dewrote in message
news:Of****************@TK2MSFTNGP06.phx.gbl...
valentin tihomirov wrote:
>[...]
If you do not want the compiler to unwind the macros generating C code,
you can avoid using macros and generate the code by your hands.

The problem is the compiler / standard has to support macros (which affect
multiple files). So to be compliant they cannot be simply removed and in
C++ commonly some proprietary workarounds like precompiled header files
are used.
[...]
They should not be unreleased. They must be released. And in your example
you forget todo so leaving them allocated (leaked).

To make the example more complete:

Instead:

CHECK(resource1 = allocate1())
CHECK(resource2 = allocate2())
CHECK(resource3 = allocate1())

in my example you would write:

if (!create()) destroy();

or assuming that exceptions are thrown:

try { create(); } catch(System.Exception e) { destroy(); }
>Don't you understand that you need to exit the function in case of error.

Where is the difference if a macro returns an error or throws an exception
or a function ?
Oh dear. Obviously, there is some difference if the exceptions were
introduced. But the point is to emulate exceptions in non-OOP languages,
those which luck exceptions. And the macros do it. Yet the solution is not
complete as they must wrap functions explicitly, do not record stack trace
and error message. I beleive the last two can be cured.
Your macro will only reduce code like:

if (!WIN32_CHECK(value, "log function")) return false;
if (!WIN32_CHECK(value, "log function")) return false;
if (!WIN32_CHECK(value, "log function")) return false;

to (Macros used):

WIN32_CHECK(value, "log function");
WIN32_CHECK(value, "log function");
WIN32_CHECK(value, "log function");
Not only. See another branch. Macros also defer evaluation till it is really
needed.

The problem is - if you read the code you can't see what the macro is
doing. How do I know if it leaves the function ?
How do you know that 'throw e' leaves the function?
For this kind of error handling IMHO exceptions have to be used.
Oh dear. I do marcos exactly to mimic exceptions in the language which lacks
them.

The big problem IMHO in C# and C is that a programmer has to care about
exceptions too much, if a locally allocated object uses resources. Meaning
that you have to call Dispose manually.
Fortunately there is

using (....) {}

in C# which at least helps for local function scope.
Oh dear, using does the job of finally:
resourse = allocate();
try
use(resourse);
finally
close(resourse);
end;
I'm not sure that the 'using' brings much advantage here. The 'finally' is
more capable as it is not fixed to IDisposable clean up method.
>And this is the function which invokes the checking routine rather than
the checking routine. You cannot raise an exception in C/C++ in the
ellipsys.

Why not ? And in C++ you don't have to care if an exception is raised. The
compiler calls destructors automatically. In C# you don't have to care
only about objects holding resources (file handles, etc.).
In C you have to care about everything.

My data tells me that there are no exceptions is C++ (excepting proprietary
solutions which lack try-finally, and are useless therefore). The issue is
not whether I have to care about everything in C/C++. The question is how
can I minimize the effort on controlling dynamically allocated resoureses.

In C++ resources are also freed if an exception is thrown in an objects
constructor. Though I wouldn't do this anyways. Neither in C# nor in any
other program language. Just because of the problems we are discussing
about.
I may mistake but Delphi invokes destructors automatially as well on
partially created objects. But it is silly to initialize-flag every resourse
to be allocated and then cheking the frag before free. It is more rational
to figure out the level of object construction and start destroying
unconditionally from that point.

You claimed that in OOP you have to write:

##[start of quote]
void create() {
allocate1();
try {
allocate2();
try {
allocate3();
try {
allocate_last();
} catch {
destroy(label3);
throw;
}
} catch {
destroy(label2);
throw;
}
} catch {
destroy(label1);
throw;
}

"
##[end of quote]

I just claimed that you can do it:

Object o1 = null;
Object o2 = null;

try
{
.....
}
catch(System.Exception)
{
o1.Dispose(); // destroy - meaning freeing resources
o2.Dispose(); //
}
Won't you get "NullPointerException"? The majority suggests to perform
checks before release. Peahaps, we do not need exceptions if we like
checking conditions explicitly?

But commonly in C# you don't have to care about, if the objects don't hold
any resources which immediately have to be freed.
GC cares about nothing besidies memory.
I think rather the ternary operator would not directly match to
if-then-else but rather to a helper function:

func(Select(cond, a, b), Select(cond, x, y));

int Select(bool condition, int a, b)
{
if (condition) return a;
return b;
}
??? The Multiplexer function you entail is not anyhow better than the
ternary operator -- it has the same parameters and functionality. In
addition, it has a defect -- arguments are evalueated eagerly rather than
lazily leading to failures in situations like
print(e == null ? 'null' : e.Message)

But if authority denies ternary operators while still allowing reusable
functions (can we program without functions?) -- it will get the flawed
Select functions in return.
Jun 11 '07 #44

P: n/a
valentin tihomirov wrote:
[...]
>The problem is - if you read the code you can't see what the macro is
doing. How do I know if it leaves the function ?

How do you know that 'throw e' leaves the function?
Well if you don't catch it somewhere you will now ;-).
A return value can be silently left unhandled.
[...]
Oh dear, using does the job of finally:
Don't think so. You don't have to explicitly write and think about
adding a Dispose call.
>[...]
I'm not sure that the 'using' brings much advantage here. The 'finally' is
more capable as it is not fixed to IDisposable clean up method.
You could create an object which gets a reference to the resources to
handle which it releases in the Dispose method.
Mimics C++ RAII (somewhat).
[...]
My data tells me that there are no exceptions is C++ (excepting proprietary
solutions which lack try-finally, and are useless therefore). The issue is
not whether I have to care about everything in C/C++. The question is how
can I minimize the effort on controlling dynamically allocated resoureses.
C++ works totally different - there is "no finally needed".
[...]
I may mistake but Delphi invokes destructors automatially as well on
Yes, AFAIK.
partially created objects. But it is silly to initialize-flag every resourse
to be allocated and then cheking the frag before free. It is more rational
to figure out the level of object construction and start destroying
unconditionally from that point.
Well as I already wrote, in C++ this initialize list is handled by the
compiler automatically. In C# I miss RAII somewhat, though I can live
with using blocks.
>[...]
>I just claimed that you can do it:

Object o1 = null;
Object o2 = null;

try
{
.....
}
catch(System.Exception)
{
o1.Dispose(); // destroy - meaning freeing resources
o2.Dispose(); //
}

Won't you get "NullPointerException"? The majority suggests to perform
Sorry yes my fault. You have to check it before. Forgot the check.
[...]
>But commonly in C# you don't have to care about, if the objects don't hold
any resources which immediately have to be freed.

GC cares about nothing besidies memory.
As I said - if resources don't have to freed immediately.
You can release resources in a finalizer, but that may be (commonly) too
late - if it's ever is called.
>
[...]
Andre
Jun 11 '07 #45

P: n/a
My data tells me that there are no exceptions is C++ (excepting
proprietary solutions which lack try-finally, and are useless therefore).
The issue is not whether I have to care about everything in C/C++. The
question is how can I minimize the effort on controlling dynamically
allocated resoureses.
By which you show again a complete lack of C++ knowledge. Exceptions are
part of the ISO standard language, and have been for quite some time.
Destructors are not limited to stack variables, subobjects are destructed
100% automatically when the parent object dies whether by:

(1) constructor failure, throwing exception
(2) delete operator called
(3) leaving scope of an automatic (stack) variable
(4) embedded in yet another object which was destroyed

This is the foundation of RAII. You will become a much better programmer if
you study some examples, before telling us about all the things C++ can't
do, when in reality RAII provides them perfectly.

Jun 12 '07 #46

P: n/a
It certainly doesn't - and neither does the CLI specification. Claiming
that either of them *do* have destructors has been a cause of confusion
for those who then expect C++ destructor semantics (where the
destructor is automatically called).
C++/CLI does implement the usual destructor semantics for ref classes as
well as native, invoking IDisposable when the object leaves scope / parent
object is destroyed.

See "Stack Semantics" in the C++/CLI docs.

Jun 12 '07 #47

P: n/a

"valentin tihomirov" <V_*********@best.eewrote in message
news:ea**************@TK2MSFTNGP06.phx.gbl...
1. He went to home.
2. A gived individual of man sex consciously performed a process of foot
transportation with normal speed in past time towards an object, which
represents a place of permanent resedence of given subject.
3. He homeward went.

Now 1 and 3 are essentially the same length and complexity. In fact, 3
eliminates a preposition. Is 3 therefore preferred?

Jun 12 '07 #48

P: n/a
On Jun 12, 7:59 am, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
It certainly doesn't - and neither does the CLI specification. Claiming
that either of them *do* have destructors has been a cause of confusion
for those who then expect C++ destructor semantics (where the
destructor is automatically called).

C++/CLI does implement the usual destructor semantics for ref classes as
well as native, invoking IDisposable when the object leaves scope / parent
object is destroyed.

See "Stack Semantics" in the C++/CLI docs.
Right. That doesn't mean that IDisposable implementations can
reasonably be called destructors when talking in contexts other than C+
+/CLI, IMO. In particular, if a "traditional" C++ programmer hears
about destructors in the context of C#, they may well come to the
false conclusion that if they implement IDisposable, it will be called
automatically from C# code.

Jon

Jun 12 '07 #49

P: n/a
This is the foundation of RAII. You will become a much better programmer
if you study some examples, before telling us about all the things C++
can't do, when in reality RAII provides them perfectly.
I fahve seen tons of C++ examples in MSDN. Do not remember if if they ever
use any exceptions. They do everything in C style (besides object
instantiation). Macros just collapse the pattern, which constituates all the
win32 code:

handle = Create...
if (handle == invalid) {
printf(last error)
return
}
handle2 = Create ...

to mimic exceptions.

And tell me how your RAII perfectly handles these cases and how we do not
need finally. We do not need finally for the reason nobody uses exceptions
in C++.

The case of "100% automatic destruction" on explicit (manual) destructor
call is especially funny.
Jun 12 '07 #50

56 Replies

This discussion thread is closed

Replies have been disabled for this discussion.