View mode: basic / threaded / horizontal-split · Log in · Help
August 15, 2005
Where did my contracts go?
Hi,

First, I was happily coding in D under -debug. Then, I started using std.boxer
which requires that I use -release because of unresolved linking.

So I add -release (in _addition_ to -debug) and all hell breaks lose.

1) asserts no longer display anything meaningful; they segfault.
2) pre-condition (in) contracts disappear altogether.

What's going on? This seems extremely unreasonable to me.

I understand that some crazy people don't like safety contracts in their
-release code, but I specified -debug too.

Would it be possible to restore these 2 contracts, properly (no segfault), at
least under -debug? Please? I'm on linux w/ 129.

Thank you,
--AJG.
August 15, 2005
Re: Where did my contracts go?
I agree , I think contracts should be completely seperate from 'release' and
'debug'.   Looking at the front end ( mars.c : 385 ) , it wouldn't take much
at all , just an extra command line argument , -contracts or some such.

This has been talked about before , not sure what the outcome was.

Charlie

P.S. Also , in the source it has useAssert parameter set to true if
unittests are on , maybe try that ?

"AJG" <AJG_member@pathlink.com> wrote in message
news:ddqhqm$19a3$1@digitaldaemon.com...
> Hi,
>
> First, I was happily coding in D under -debug. Then, I started using
std.boxer
> which requires that I use -release because of unresolved linking.
>
> So I add -release (in _addition_ to -debug) and all hell breaks lose.
>
> 1) asserts no longer display anything meaningful; they segfault.
> 2) pre-condition (in) contracts disappear altogether.
>
> What's going on? This seems extremely unreasonable to me.
>
> I understand that some crazy people don't like safety contracts in their
> -release code, but I specified -debug too.
>
> Would it be possible to restore these 2 contracts, properly (no segfault),
at
> least under -debug? Please? I'm on linux w/ 129.
>
> Thank you,
> --AJG.
>
>
>
>
>
August 15, 2005
Re: Where did my contracts go?
"AJG" <AJG_member@pathlink.com> wrote in message 
news:ddqhqm$19a3$1@digitaldaemon.com...
> Hi,
>
> First, I was happily coding in D under -debug. Then, I started using 
> std.boxer
> which requires that I use -release because of unresolved linking.
>
> So I add -release (in _addition_ to -debug) and all hell breaks lose.
>
> 1) asserts no longer display anything meaningful; they segfault.
> 2) pre-condition (in) contracts disappear altogether.
>
> What's going on? This seems extremely unreasonable to me.
>
> I understand that some crazy people don't like safety contracts in their
> -release code, but I specified -debug too.
>
> Would it be possible to restore these 2 contracts, properly (no segfault), 
> at
> least under -debug? Please? I'm on linux w/ 129.
>
> Thank you,
> --AJG.

If you want to use boxer in a module with asserts turned on you have to 
recompile phobos with asserts turned on (ie without -release). Edit the 
makfile in dmd/src/phobos to uncomment the unittest DFLAGS variable and run 
make.
August 15, 2005
Re: Where did my contracts go?
Hi,

>If you want to use boxer in a module with asserts turned on you have to 
>recompile phobos with asserts turned on (ie without -release). Edit the 
>makfile in dmd/src/phobos to uncomment the unittest DFLAGS variable and run 
>make. 

While this helps with std.boxer specifically, it doesn't help with contracts in
general. Before anything, are the following three things clearly defined
anywhere?

A) -debug
B) -release
C) -debug -release
D) -release -debug (if different from C).

In addition, I'm really surprised (read: annoyed) that release/debug have an
effect on contracts. This is faulty logic IMHO.

It would make more sense to do the following:

# void Foo(int a) in {
#     assert(a == 42); // Stays there forever.
#     debug assert(someExpensiveCheck(a)); // Removed in release.
# } body { /* body */ }

Or perhaps, something like:

# void Foo(int a) debug in { // All removed in release.
#     assert(a == 42);
#     assert(someExpensiveCheck(a));
# } body { /* body */ }

Thanks,
--AJG.
August 15, 2005
Re: Where did my contracts go?
On Mon, 15 Aug 2005 17:02:14 +0000 (UTC), AJG wrote:

> Hi,
> 
> First, I was happily coding in D under -debug. Then, I started using std.boxer
> which requires that I use -release because of unresolved linking.
> 
> So I add -release (in _addition_ to -debug) and all hell breaks lose.
> 
> 1) asserts no longer display anything meaningful; they segfault.
> 2) pre-condition (in) contracts disappear altogether.
> 
> What's going on? This seems extremely unreasonable to me.
> 
> I understand that some crazy people don't like safety contracts in their
> -release code, but I specified -debug too.
> 
> Would it be possible to restore these 2 contracts, properly (no segfault), at
> least under -debug? Please? I'm on linux w/ 129.

Believe it or not, but this is a philosophical discussion.

Walter's philosophy (and yes, I'm speculating here) is that the purpose of
the in{} and out{} blocks and assert() calls is to alert the developer of
any mistakes in their code logic. They are not to be used to detect bad
data. The "-release" effects these constructs because by the time you
create the production edition, all the code logic has been validated.

This means that if you require that the end user is alerted to logic
errors, your choices are that you supply them with a non-release edition
and/or you code your 'contracts' outside of the in{}, out{}, and assert()
constructs. The choice is yours.

Further more, validation of user data should never be coded inside contract
constructs as these are designed to detect *logic* mistakes and not data
problems. In short, you are encouraged to detect logic errors before you
get your application to an end user, and to detect data errors within all
editions of your application.

The "-debug" switch has got absolutely nothing to do with contracts
whatsoever. The "-debug" switch has identical functionality to the
"-version" switch. There can be considered as aliases for each other.
However, the reason for using different words ('debug' vs 'version') is to
emphasize the different purposes of the conditional code. Code that is
conditionally compiled in with 'version' represents valid alternatives of
the application based on environmental, platform, or usage variations.
Those fragments of code conditionally compiled in with 'debug' represent
valid alternatives for pre-production editions. By having both 'version'
and 'debug', we can intermix there usage to create very precise editions of
the application to suit all purposes.

Yes, it is easy to confuse the debug() construct with contract programming,
but in D they are not the same. It is especially important to realize that
the "-release" switch has no effect on the debug() construct.

The "-release" switch also removes the hidden asserts (range-checking,
missing returns, etc...) as well as the explicit asserts.

As the assert() call only displays information useful to people who have
access to the source code, it is a bit pointless using asserts to alert
end-users to problems.

-- 
Derek Parnell
Melbourne, Australia
16/08/2005 7:06:17 AM
August 15, 2005
Re: Where did my contracts go?
On Mon, 15 Aug 2005 20:18:48 +0000 (UTC), AJG wrote:

> Hi,
> 
>>If you want to use boxer in a module with asserts turned on you have to 
>>recompile phobos with asserts turned on (ie without -release). Edit the 
>>makfile in dmd/src/phobos to uncomment the unittest DFLAGS variable and run 
>>make. 
> 
> While this helps with std.boxer specifically, it doesn't help with contracts in
> general. Before anything, are the following three things clearly defined
> anywhere?

Yes. In the documentation for the DMD compiler and the documentation for
conditional compilation.

> A) -debug
-debug
compile in debug code 
-debug=level
compile in debug code <= level 
-debug=ident
compile in debug code identified by ident

> B) -release
-release
compile release version, which means not generating code for contracts and
asserts

> C) -debug -release
Both the above.
> D) -release -debug (if different from C).
Same as above.

"-release" and "-debug" are totally independent from each other.

> In addition, I'm really surprised (read: annoyed) that release/debug have an
> effect on contracts. This is faulty logic IMHO.

"-debug" does not effect contracts at all. Only "-release" does.

> It would make more sense to do the following:
> 
> # void Foo(int a) in {
> #     assert(a == 42); // Stays there forever.
Why? What useful information would this give to the end user?

> #     debug assert(someExpensiveCheck(a)); // Removed in release.
> # } body { /* body */ }

You are encouraged to code such a 'contract' in this manner instead ...

void Foo(int a) 
in {
   assert(someExpensiveCheck(a)); // Removed in release.
} 
body { 
   // Input *data* validation.
   if (a == 42) Abend("In Foo(), the input data must be 42");
   /* rest of body */ 
}

-- 
Derek Parnell
Melbourne, Australia
16/08/2005 7:35:23 AM
August 16, 2005
Re: Where did my contracts go?
Hi Derek,

>>Before anything, are the following three things clearly defined
>> anywhere?
>
>Yes. In the documentation for the DMD compiler and the documentation for
>conditional compilation.

Well, I must be reading something wrong, cause...

~test.d:
# void main() {   
#     printf("Before\n");
#     assert(false);
#     printf("After\n");
# }

>> A) -debug
>-debug
>compile in debug code 
>-debug=level
>compile in debug code <= level 
>-debug=ident
>compile in debug code identified by ident

This is fine. Debug seems to work properly.

Output:
# Before
# Error: AssertError Failure test.d(3)

>> B) -release
>-release
>compile release version, which means not generating code for contracts and
>asserts

Not quite...

Output:
# Before
# Segmentation Fault

>> C) -debug -release
>Both the above.
>> D) -release -debug (if different from C).
>Same as above.

Once again, the output is:
# Before
# Segmentation Fault

>"-release" and "-debug" are totally independent from each other.

Well, sort of. What about when you don't specify _either_ one? The it is assumed
you meant -debug, right? Well, then that means there is no way to _explicitly_
set NO-debug, other than to say -release. That means, thus, that they are
related.

>> In addition, I'm really surprised (read: annoyed) that release/debug have an
>> effect on contracts. This is faulty logic IMHO.
>"-debug" does not effect contracts at all. Only "-release" does.

Doesn't seem to be that way. -release makes asserts segfault.

>> It would make more sense to do the following:
>> 
>> # void Foo(int a) in {
>> #     assert(a == 42); // Stays there forever.
>Why? What useful information would this give to the end user?

It's _not_ about the user. It's about basic function safety. Why have a section
called "in," where you are supposed to check for pre-conditions, when that
section is effectively _useless_ in real code? This is a bad design decision,
IMHO.

Asserts are a simple and elegant way to prevent bizarre and potentially
catastrophic behaviour that you don't expect to happen in real code, but just
_might_. When debugging, they are useful tools to the programmer. But they are
doubly useful: In real code, they are last-resort, emergency guards.

Well, you say, throw an exception. You want me to instead throw an exception
every time I have an assert? The sheer verbosity will kill you. For every:

assert(c);

You must use:

if (!c) throw new Exception("Error: AssertError Failure ajg.module.d(13)");

Look at that monster. If you pepper your code with Exceptions where regular
asserts would have sufficed, you are looking at some serious code bloat. Just
like const, the meaning is lost in all that pomposity and syntax. Assert, on the
other hand is concise and elegant. Therefore, I use asserts a lot, because I
would want my code to be bulletproof.

Moreover, there are even more disadvantages:

1) It's a heck of a lot more work. You are less likely to do it.
2) You lose automatic module/line-number indications.
3) It's a more complex construct.
4) Thus, you lose the immediate, quick, straight-forward meaning. An assert is a
simple guard. You see it an you know that condition must never happen. 

OTOH, an exception is a much more powerful error-handling facility. When I put
an assert, I don't want to handle an error, I want execution to come to a
screeching halt lest the situation get even worse.

Well, use a _function_ that throws an exception, you say. I suppose that's what
your "Abend" function does, right? First off, still quite verbose:

# // Assuming this:
# void assert2(int c, string m) { 
#     if (!c) throw new Exception("Error: AssertError Failure " ~ m); 
# }

assert(c);
vs.
assert2(c, "ajg.module.d(13)");

Even more problems:

1) It's a lot more work. Harder to maintain.
2) Still no automatic module/line-number.
3) Even worse, now the exception will seem to originate in a completely
different, generic place. Bad!
4) The compiler has no knowlege of the fact that the function is a special one,
designed specifically to throw. So it can't detect dead code. It also can't
"know" what you mean when you say assert(false).
5) Replacing a built-in _language_ facility with a hack is just ridiculous.
That's why there is assert() in the first place.

>You are encouraged to code such a 'contract' in this manner instead ...
> void Foo(int a) 
> in {
>    assert(someExpensiveCheck(a)); // Removed in release.
> } 
> body { 
>    // Input *data* validation.
>    if (a == 42) Abend("In Foo(), the input data must be 42");
>    /* rest of body */ 
> }

Two things:

1) Once again, it's not only about user-input validation. It's about validation
of preconditions in general. These can, for example, be parameters that can come
from anywhere. They can come directly from the end user, or from another
programmer, or from a corrupted stack, or from god knows where.

But it doesn't even have to be parameters. It can be any sort of precondition.
Having enough memory. A thread having stopped. A variable having been set. A
mutex having been released. Anything. It makes sense to put these things in a
section called "in," which is specifically designed to check for pre-conditions.

You mean to say all these things magically dissapear in production code? If
that's the "philosophy," then that's quite dangerous and naive. It's exactly the
_other_ way around, these things become more likely to happen (uncontrolled,
distinct environment(s)) and much more likely to be seriously harmful (real,
important data/systems at stake).

2) Also, why bother having an "in" section in the first place? This just creates
a mess. You must split your "real" checks from the fake ones into two sections,
when the "in" one could nicely handle both. This split would be fine for one
function, but not for all. It's very distracting.

Cheers,
--AJG (linux w/ 129).

PS: As you can tell, I am pro-assert, and pro-in. In other words, pro-safety.
You must always practice safe hex, people! ;)
August 16, 2005
Re: Where did my contracts go?
Derek Parnell wrote:
> On Mon, 15 Aug 2005 17:02:14 +0000 (UTC), AJG wrote:
> 
> 
>>Hi,
>>
>>First, I was happily coding in D under -debug. Then, I started using std.boxer
>>which requires that I use -release because of unresolved linking.
>>
>>So I add -release (in _addition_ to -debug) and all hell breaks lose.
>>
>>1) asserts no longer display anything meaningful; they segfault.
>>2) pre-condition (in) contracts disappear altogether.
>>
>>What's going on? This seems extremely unreasonable to me.
>>
>>I understand that some crazy people don't like safety contracts in their
>>-release code, but I specified -debug too.
>>
>>Would it be possible to restore these 2 contracts, properly (no segfault), at
>>least under -debug? Please? I'm on linux w/ 129.
> 
> 
> Believe it or not, but this is a philosophical discussion.

Why then does the overview page say:
"D (...) doesn't come with (...) an overriding philosophy."
http://www.digitalmars.com/d/overview.html

and um, I think the word "philosophy" has different meanings in 
different context, and in the context of your post, it means "principle" 
or "idea"..

so if we debate the meaning of "-release" it wouldn't really be a 
/philosophical/ discussion, because we're not debating the nature of 
time and space :P

From answers.com:
http://www.answers.com/philosophy&r=67
2. Investigation of the nature, causes, or principles of reality, 
knowledge, or values, based on logical reasoning rather than empirical 
methods.

7. A set of *ideas or beliefs* relating to a particular field or 
activity; an underlying theory: /an original philosophy of advertising/.


> 
> Walter's philosophy (and yes, I'm speculating here) is that the purpose of
> the in{} and out{} blocks and assert() calls is to alert the developer of
> any mistakes in their code logic. They are not to be used to detect bad
> data. The "-release" effects these constructs because by the time you
> create the production edition, all the code logic has been validated.
> 
> This means that if you require that the end user is alerted to logic
> errors, your choices are that you supply them with a non-release edition
> and/or you code your 'contracts' outside of the in{}, out{}, and assert()
> constructs. The choice is yours.
> 
> Further more, validation of user data should never be coded inside contract
> constructs as these are designed to detect *logic* mistakes and not data
> problems. In short, you are encouraged to detect logic errors before you
> get your application to an end user, and to detect data errors within all
> editions of your application.
> 
> The "-debug" switch has got absolutely nothing to do with contracts
> whatsoever. The "-debug" switch has identical functionality to the
> "-version" switch. There can be considered as aliases for each other.
> However, the reason for using different words ('debug' vs 'version') is to
> emphasize the different purposes of the conditional code. Code that is
> conditionally compiled in with 'version' represents valid alternatives of
> the application based on environmental, platform, or usage variations.
> Those fragments of code conditionally compiled in with 'debug' represent
> valid alternatives for pre-production editions. By having both 'version'
> and 'debug', we can intermix there usage to create very precise editions of
> the application to suit all purposes.
> 
> Yes, it is easy to confuse the debug() construct with contract programming,
> but in D they are not the same. It is especially important to realize that
> the "-release" switch has no effect on the debug() construct.
> 
> The "-release" switch also removes the hidden asserts (range-checking,
> missing returns, etc...) as well as the explicit asserts.
> 
> As the assert() call only displays information useful to people who have
> access to the source code, it is a bit pointless using asserts to alert
> end-users to problems.
>
August 16, 2005
Re: Where did my contracts go?
Hi,

>I agree , I think contracts should be completely seperate from 'release' and
>'debug'.   Looking at the front end ( mars.c : 385 ) , it wouldn't take much
>at all , just an extra command line argument , -contracts or some such.

I'm glad someone agrees. Another pro-safety feller I see ;) 

Indeed, a -contract argument would work well. Contracts should _always_ be
enforced IMO. But I understand this isn't likely to happen. So, at least the
choice to enforce them should be given independent of debug/release.

For the tuning/tweaking crowd, a more fine-grained version could be offered:

-contracts // all
-contracts:in // preconditions
-contracts:assert // asserts
etc.

>This has been talked about before , not sure what the outcome was.

Walter?

>Charlie

>P.S. Also , in the source it has useAssert parameter set to true if
>unittests are on , maybe try that ?

Not sure what you mean. Which source?

Cheers,
--AJG.
August 16, 2005
Re: Where did my contracts go?
Hi,

>> Would it be possible to restore these 2 contracts, properly (no segfault), at
>> least under -debug? Please? I'm on linux w/ 129.
>
>Believe it or not, but this is a philosophical discussion.

This is all well and good, but D is supposed to be borne out of practice. The
current "philosophy" as it were doesn't seem very pragmatic. See below.

>Walter's philosophy (and yes, I'm speculating here) is that the purpose of
>the in{} and out{} blocks and assert() calls is to alert the developer of
>any mistakes in their code logic. They are not to be used to detect bad
>data. The "-release" effects these constructs because by the time you
>create the production edition, all the code logic has been validated.

Walter, could you confirm this? If it's true, this is not good news for safety.

>This means that if you require that the end user is alerted to logic
>errors, your choices are that you supply them with a non-release edition
>and/or you code your 'contracts' outside of the in{}, out{}, and assert()
>constructs. The choice is yours.

The only choice I see is between safe (debug) and unsafe(release). I understand
if you want the marginal extra speed of the unsafe version, but perhaps this
safety (aka contracts) could be made into a separate option?

"Release" code should have nothing to do with contracts or safety. It should be
about removing extra symbols, stripping useless sections, etc. Not safety. Not
contracts. Well, IMHO, of course.

Release is already sort-of indendent of debug. Fine. Couldn't it also be
independent of contracts? This would solve a lot.

>Further more, validation of user data should never be coded inside contract
>constructs as these are designed to detect *logic* mistakes and not data
>problems. In short, you are encouraged to detect logic errors before you
>get your application to an end user, and to detect data errors within all
>editions of your application.

Could I get a precise definition of a logic mistake vs. a "data" mistake,
please? I would think the two are intertwined. Thus, there is only _one_ kind of
error coming into a function: a pre-condition. Everything falls into that.

The in block is _specifically_ stated to take care of pre-conditions. But it
fails in -release. It leaves the code unprotected against unexpected failing
pre-conditions. It's as simple as that: No pre-condition protection. No safety.

>By having both 'version'
>and 'debug', we can intermix there usage to create very precise editions of
>the application to suit all purposes.

I don't see where you are getting all that "precision," since a single -release
(even with -debug(s)) wipes out all in/out contracts and causes asserts to
segfault. That's kind of un-precise. Rather, it's kind of blunt.

>Yes, it is easy to confuse the debug() construct with contract programming,
>but in D they are not the same. It is especially important to realize that
>the "-release" switch has no effect on the debug() construct.

Yes, it's counter-intuitive. Traditionally, release and debug are mutually
exclusive (as they should be), since they are contradicting terms. But not in D.
Great. How is this a good thing?

>The "-release" switch also removes the hidden asserts (range-checking,
>missing returns, etc...) as well as the explicit asserts.

This is insane. So IndexOutOfBounds checks are _gone_ in release? So I guess
arrays will _NEVER_ be overrun in production code, right? Because as we know,
_all_ bugs are solved during the initial design. Yeah, good thinking.

>As the assert() call only displays information useful to people who have
>access to the source code, it is a bit pointless using asserts to alert
>end-users to problems.

Uh... no. A human-readable line like:

"Error: AssertError Failure ajg.module.d(13)"

is:
1) A lot friendlier nasty segfault.
2) More understandable.
3) QUITE useful. The user could actually send this message to customer support,
or when submitting a bug report, etc.

The idea that asserts (or worse, contracts in general) are only useful to the
immediate programmer is misguided.

Cheers,
--AJG.
« First   ‹ Prev
1 2 3
Top | Discussion index | About this forum | D home