assume, assert, enforce, @safe

H. S. Teoh via Digitalmars-d digitalmars-d at puremagic.com
Fri Aug 1 16:46:20 PDT 2014


On Fri, Aug 01, 2014 at 11:24:29PM +0000, bearophile via Digitalmars-d wrote:
> 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).
[...]

I know, I wish I had the time and the know-how to actually implement
this in dmd. I'm tired of the all-talk-and-no-action on the forum. Is
there at least an enhancement request for this though?

The point about delegates is kinda interesting, though. Can they
actually have contracts attached to them? I'd like to think that the
contracts really ought to attach to the *type* of the delegate rather
than the delegate itself. The reason is that I don't see how it would
make sense if you had something like this:

	alias DgType = int delegate(int);

	int f1(int x) in { assert(x < 0); } body { ... }
	int f2(int x) in { assert(x > 0); } body { ... }

	// How does the following make any sense?
	void func(DgType dg, int x) {
		// How are we supposed to know what values of x are
		// acceptable?
		dg(x);
	}

	func(&f1, 1);	// oops
	func(&f2, -1);	// oops

Basically, given a DgType of unknown origin, it's impossible to reliably
tell what arguments you ought to pass to it. So the compiler wouldn't
know which in-contract to insert in func().

OTOH, perhaps one way to work around this, is to have a function with an
in-contract compile into a preamble and a body:

	int func(int x)
	in { assert(x > 5); }
	body {
		return computeResult(x);
	}

would compile to the equivalent of:

	int __func_incontract(int x) {
		assert(x > 5);
		goto __func_body;	// fall through to __func_body
	}
	int __func_body(int x) {
		return computeResult(x);
	}

In non-release mode, calls to func would get translated into calls to
__func_incontract, but in release mode, calls to func get translated
into direct calls to __func_body. In both cases, the compiler always
emits both __func_incontract and __func_body. If the ..._incontract
symbols are never referenced by the final program, the linker discards
them at link time.

This can be applied to both normal functions and delegates. In
non-release mode, the (address of the) delegate would point to its
..._incontract portion, whereas in release mode, the (address of the)
delegate would point directly to its ..._body portion. This way, if the
caller is compiled in release mode, it will skip the contract, but if
called in non-release mode, it will run the contract.


T

-- 
MACINTOSH: Most Applications Crash, If Not, The Operating System Hangs


More information about the Digitalmars-d mailing list