August 01, 2014
On Friday, 1 August 2014 at 21:51:10 UTC, H. S. Teoh via Digitalmars-d wrote:
> On Fri, Aug 01, 2014 at 09:42:06PM +0000, Jonathan M Davis via Digitalmars-d wrote:
>> On Friday, 1 August 2014 at 14:10:14 UTC, Sean Kelly wrote:
> [...]
>> But we probably would be better off if none of the switches had names
>> like -release or -debug so that folks actually had to figure out what
>> they did before using them rather than simply assuming that one is for
>> release builds and the other is for debug builds.
> [...]
>
> Great. So let's rename all of dmd's command-line options to -a, -b, -c,
> -d, -e, -f, ... (in arbitrary order). As long as we document it all, it
> will work just perfectly fine, right? After all, it *does* force users
> to *really* know what each option does. :-D

LOL. That would be stupid. No, what would make sense would be something like --remove-assertions.

But regardless, I'm not advocating that we change the switches. I don't think that it's a big enough problem to merit that. But I do think that we could have picked better names.

The one that always stumps me though is -debug. It's a bad name, because it makes people think debug/release, when all it does is enable debug blocks, and it can actually be used in release builds, but given that they're debug blocks, -debug makes sense. And I can't think of a better name for it. But even if I could think of a better name, I think that we're stuck with -debug at this point.

- Jonathan M Davis
August 01, 2014
On Friday, 1 August 2014 at 21:42:07 UTC, Jonathan M Davis wrote:
> On Friday, 1 August 2014 at 14:10:14 UTC, Sean Kelly wrote:
>> On Friday, 1 August 2014 at 08:21:28 UTC, Kagamin wrote:
>>> On Thursday, 31 July 2014 at 21:29:59 UTC, Sean Kelly wrote:
>>>> So effectively, any factor occurring at runtime.  If I create a
>>>> library, it is acceptable to validate function parameters using
>>>> assert() because the user of that library knows what the library
>>>> expects and should write their code accordingly.  That's fair.
>>>
>>> He should, but what if he doesn't and the library is phobos or druntime (which are compiled in release mode)? BTW, druntime can't use enforce and doesn't verify its input.
>>
>> Druntime uses contracts and asserts in places. Which are of course removed because we ship only a "release" build.  Once again, the worst naming for a compiler switch ever. What I really want is a way to ship release and non-release builds (ie. checked and unchecked) and have the proper one chosen at link time based on build flags. Basically toss the -defaultlib and -debuglib and replace it with -checkedlib and -uncheckedlib.
>
> Well, to be fair, it's pretty standard practice to remove all assertions in release builds in other languages. If anything, leaving them in is highly abnormal. Sure, there are reasons to do it, but most folks don't. So, while I can see why you don't like the switch being called -release, it's behavior matches what most people would do for release builds.

But is it what they *should* do?  Quoting Matthew Wilson's "The
Nuclear Reactor and the Deep Space Probe"
(http://www.artima.com/cppsource/deepspaceP.html):

"Assertions in C and C++ tend to be included in debug builds
only, and elided in release builds for performance reasons.
However, as the programming community appreciation for contract
programming grows, there is increasing interest in using contract
enforcement in release builds. Indeed, as we'll see in part 4 of
this article, there is a very good argument for leaving contracts
in released software, since the alternative may be worse,
sometimes catastrophically so."

I wish the rest of the series were available online.  I think I
had copies of later versions but can't find them.
August 01, 2014
On Friday, 1 August 2014 at 20:57:29 UTC, Walter Bright wrote:
> On 8/1/2014 12:47 PM, Tofu Ninja wrote:
>> Having your augment consistently dismissed by "I see no difference" or "That is
>> misuse" is frustrating to say the least.

Indeed.

> I repeatedly gave detailed rationales for that.

Unfortunately these "detailed rationales" consisted mostly of attacking straw men, and some other unsound arguments :(

My last reply to you is still unanswered if you want to give it another try. I feel like it's getting pretty childish though, so I'm also very close to giving up on this topic. So much back-and-forth we can't even get past definitions of assert and assume, or even agree that there is a difference between the two... never mind discussing the real issues here. And there definitely are real issues with your proposal to make -release transform all asserts into assumes.
August 01, 2014
On Fri, Aug 01, 2014 at 03:34:00PM -0700, Walter Bright via Digitalmars-d wrote:
> On 8/1/2014 2:50 PM, Jonathan M Davis wrote:
> >Thinking about it, I'm actually wondering if I should use assertions _more_ so that the compiler might be able to do better optimizations in -release.
> 
> I think this will be a productive strategy once this gets implemented in optimizers.
> 
> Of course, using them effectively will not be easy unless one is willing to understand how data flow analysis works and is willing to examine the generated code.

Actually, I'm thinking of ways of extending this even further, such that asserts can become the vehicle for user-defined types to declare high-level optimizations.

For example, a matrix type could declare that certain matrix expressions are equivalent, thereby allowing the optimizer to substitute one for the other to simplify matrix expressions where it couldn't before, because it doesn't know how to infer such equivalences when overloaded operators may have arbitrary code in their implementation.

I haven't thought about the syntax for this yet, but the idea is something like this:

	struct Matrix {
		// Implement overloaded operators here
		Matrix opBinary(string op)(Matrix m) { ... }

		Matrix transpose() { ... }

		// (THIS IS TENTATIVE, HYPOTHETICAL SYNTAX) Declare
		// identities the optimizer might use for Matrix
		// expressions
		invariant(Matrix a, Matrix b, Matrix c) {
			// Tell optimizer that Matrix obeys
			// distributivity law
			assert(a*b + a*c == a*(b+c));

			// Tell optimizer about multiplicative identity
			assert(!a.isIdentity || a*b == b);

			// Tell optimizer about idempotence of
			// .transpose
			assert(a.transpose().transpose() == a);
		}
	}

	void main() {
		Matrix x, y, z;
		auto r1 = x*y + x*z; // gets simplified into w = x*(y+z)

		auto I = Matrix.identity();
		assert(I.isIdentity);
		auto r2 = I*x; // gets simplified to r2 = x

		auto r3 = x.transpose;
		auto r4 = r3.transpose; // gets simplified to r4 = x
	}

I think this will be a very powerful feature to further narrow the gap between built-in types vs. library-defined types.


T

-- 
Never trust an operating system you don't have source for! -- Martin Schulze
August 01, 2014
On Friday, 1 August 2014 at 22:34:02 UTC, Walter Bright wrote:
> On 8/1/2014 2:50 PM, Jonathan M Davis wrote:
>> Thinking about it, I'm actually wondering if I should use assertions _more_ so
>> that the compiler might be able to do better optimizations in -release.
>
> I think this will be a productive strategy once this gets implemented in optimizers.
>
> Of course, using them effectively will not be easy unless one is willing to understand how data flow analysis works and is willing to examine the generated code.

True, but as long as the runtime cost isn't too great for your debug builds, having assertions for whatever conditions you think your code relies on and would ideally be checked is quite beneficial. Any optimizations by the compiler would then be a bonus, but the fact that they exist does offset the costs to debug builds somewhat (depending on what you're doing) by improving the release builds. I would think that any attempt to specifically craft assertions to aid the optimizer would be something that should generally be left to the cases where you really care about getting extra speed out of your program and are doing micro-optimizations based on profiling and the generated assembly and whatnot.

- Jonathan M Davis
August 01, 2014
On Fri, Aug 01, 2014 at 10:34:20PM +0000, Sean Kelly via Digitalmars-d wrote:
> On Friday, 1 August 2014 at 16:52:00 UTC, Daniel Murphy wrote:
> >"Sean Kelly"  wrote in message news:tngnltzwxprebpbcdkgm@forum.dlang.org...
> >
> >>Druntime uses contracts and asserts in places. Which are of course removed because we ship only a "release" build.  Once again, the worst naming for a compiler switch ever. What I really want is a way to ship release and non-release builds (ie. checked and unchecked) and have the proper one chosen at link time based on build flags. Basically toss the -defaultlib and -debuglib and replace it with -checkedlib and -uncheckedlib.
> >
> >While shipping a debug version of druntime would be useful, I think the real problem is that checking preconditions is disabled by the callee!  If preconditions are violated, the error is in the caller, and checking should be enabled based on the application's flags.
> 
> Exactly.  When the user builds with -release set, DMD should link the unchecked libphobos.  And without this flag it should link the checked build.  So the user choice of whether to use contracts extends at least to the standard library.
[...]

I don't like this. This would mean that every D library, whether it's Phobos or some 3rd party library, must now ship with checked & unchecked versions, if they want DbC to work.

IMO the correct solution is for the compiler to insert preconditions at the calling site, rather than the callee. The separate compilation problem can be solved by having dmd include preconditions in .di files so that binary-only distributions will still work.


T

-- 
There are two ways to write error-free programs; only the third one works.
August 01, 2014
On Friday, 1 August 2014 at 23:13:28 UTC, H. S. Teoh via Digitalmars-d wrote:

> IMO the correct solution is for the compiler to insert preconditions at the calling site, rather than the callee.

If we had that, I'd actually start using in blocks. As it is, I think that they're useless except when inheritance is involved, and they're more verbose than just putting the assertions at the top of the function, so I don't bother with the in block.

But certainly, in principle, I agree that whether contracts are used would depend on the flags used when compiler the caller, not the callee, but the separate compilation model does throw some kinks in that. But even if it just worked in cases where the source code was available, it would be an improvement.

- Jonathan M Davis
August 01, 2014
H. S. Teoh:

> IMO the correct solution is for the compiler to insert preconditions at the calling site,

I have seen this suggestion tens of times, but nothing has happened. (delegates make the management of contract blame more compex).

Bye,
bearophile
August 01, 2014
On 08/02/2014 01:19 AM, Jonathan M Davis wrote:
>
> If we had that, I'd actually start using in blocks. As it is, I think
> that they're useless except when inheritance is involved,

And when it is involved, they are broken because the compiler insists on removing them on each override by default.
August 01, 2014
On 8/1/2014 4:12 PM, Jonathan M Davis wrote:
> True, but as long as the runtime cost isn't too great for your debug builds,
> having assertions for whatever conditions you think your code relies on and
> would ideally be checked is quite beneficial. Any optimizations by the compiler
> would then be a bonus, but the fact that they exist does offset the costs to
> debug builds somewhat (depending on what you're doing) by improving the release
> builds. I would think that any attempt to specifically craft assertions to aid
> the optimizer would be something that should generally be left to the cases
> where you really care about getting extra speed out of your program and are
> doing micro-optimizations based on profiling and the generated assembly and
> whatnot.

The optimizations thus enabled would be the same as in, say, an if body:

    if (expr) {
       ... take advantage of expr being true ...
    }

and optimizers already do that to an increasing extent.