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

  • Thread starter Thread starter valentin tihomirov
  • Start date Start date
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.



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.




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.

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.
 
valentin said:
[...]
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 ?

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
 
valentin tihomirov said:
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.
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).
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.
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.
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.
 
Andre Kaufmann said:
valentin said:
[...]
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.


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.
 
valentin said:
[...]
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
 
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.
 
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.
 
valentin tihomirov said:
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?
 
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
 
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.
 
Now 1 and 3 are essentially the same length and complexity. In fact, 3
eliminates a preposition. Is 3 therefore preferred?

Ok, I will not tell which of 1 and 3 is better/more beautiful. The issues is
not the numer of letters. The issue is that you should repeat the same
pattern over and over again. And duspute reduction. Which is stupid.
 
valentin said:
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.

The first sentence doesn't specify the means of transportation, it can
just as well mean that he went by car. Neither does it specify the speed
of the transportation.

Also, "to home" doesn't even specify that it was his own home. It could
be anybodys home.

I am aware that you probably meant "He walked home", but this
demonstrates how redundancy makes a sentence clearer. Eventhough the
second sentence contains more errors than the first, it's still clear
what it means.

The same happens if a programming language is too terse. The compiler
can't help you spot faulty code, as the code may still be valid but
means something completely different.

(Isn't it funny when you can use someones example to argue the opposite
of the point he was trying to make? ;)
 
valentin tihomirov said:
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:

MSDN doesn't use C++ for examples, because Win32 API is pure C.
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++.

C++ destructors are called during exception stack unwinding. No finally
block is ever needed.

I don't understand what makes you incapable of researching RAII so that I
have to tell you about it. Try http://en.wikipedia.org/wiki/RAII
The case of "100% automatic destruction" on explicit (manual) destructor
call is especially funny.

That was when the _parent_ object is explicitly destructed, the child
objects are automatically destroyed.
 
C++ destructors are called during exception stack unwinding. No finally
block is ever needed.

I speak about dynamically created objects. Your RAII does not apply to
heap-allocation.

byte* buf = allocatemesomedata(size); // will this be freed in case of
exception?
AbstractClass o = new Subclass(); // will the destructor of 'o' be called
automatically?

Anyway, RAII dow not address the problem of partially created objects.
 
valentin said:
I speak about dynamically created objects. Your RAII does not apply to
heap-allocation.

Don't think so.

Smart pointers are for example used for heap allocated objects.
E.g.: boosts shared_ptr (AFAIK will be part of the next C++ standard)

shared_ptr said:
byte* buf = allocatemesomedata(size); // will this be freed in case of
exception?
AbstractClass o = new Subclass(); // will the destructor of 'o' be called
automatically?

Yes if you use boosts smart pointers or auto_ptr of the C++ library:

Anyway, RAII dow not address the problem of partially created objects.

Why ? Partially constructed objects will be destroyed partially - if you
are using RAII and not plain pointers.

RAII is very powerfull. One of the (only) reasons I still use C++.

Andre
 
Why ? Partially constructed objects will be destroyed partially - if you
are using RAII and not plain pointers.

RAII is very powerfull. One of the (only) reasons I still use C++.


How does RAII knows how far the resourse allocation has reached? How does it
jump to the point in the destructor to free only the allocated objects? The
case switch is ideal to jump to that point.

That was the origin of this discussion branch. BTW, those who thing that the
'switch' is an n-ary variation of bivalent 'if', it would be more
reasonable embrace the conditional code into {} as it matches in Pascal
rather than using 'break's, which are loop-breaking statements. The code in
loops is normally "falls through" from one instruction to the following.
 
valentin said:
How does RAII knows how far the resourse allocation has reached? How does it
jump to the point in the destructor to free only the allocated
objects? The

Well I'm not that experienced in compiler technology.
Simplified I would describe it this way:

The compiler holds a list with pointers to the destructors of the
created objects and simply calls them in reverse order, if anything goes
wrong (exception) or the object is destroyed.

Andre
 
Back
Top