Proposal for design of 'scope' (Was: Re: Opportunities for D)

H. S. Teoh via Digitalmars-d digitalmars-d at puremagic.com
Thu Jul 10 11:15:19 PDT 2014


On Thu, Jul 10, 2014 at 01:56:39PM +0200, Jacob Carlborg via Digitalmars-d wrote:
> On 10/07/14 01:57, H. S. Teoh via Digitalmars-d wrote:
> 
> >[...]
> >I'm sure there are plenty of holes in this proposal, so destroy away.
> >;-)
> 
> You should post this in a new thread.

Done.


> I'm wondering if a lot more data can be statically allocated. Then
> passed by reference to functions taking scope parameters. This should
> be safe since the parameter is guaranteed to outlive the function
> call.

Yep. In whatever shape or form we finally implement 'scope', it would
allow us to address such issues.


On Thu, Jul 10, 2014 at 01:26:54PM +0000, Wyatt via Digitalmars-d wrote:
> On Wednesday, 9 July 2014 at 23:58:39 UTC, H. S. Teoh via Digitalmars-d
> wrote:
> >
> >So here's a first stab at refining (and extending) what 'scope'
> >should be:
> >
> In general, I like it, but can scopedness be inferred?  The impression
> I get from this is we're supposed to manually annotate every scoped
> everything, which IMO kind of moots the benefits in a broad sense.

I think in some cases it can be inferred. For example, taking the
address of a local variable should return an appropriately-scoped
pointer type, so that the type system can statically verify that it
doesn't leak past the variable's lifetime:

	int* myFunc(int* q) {
		int x;
		auto ptr = &x;	// typeof(ptr) == scoped(int*) with lifetime == x.lifetime
		if (cond)
			return q;	// OK, q has infinite lifetime
		else
			return ptr;	// compile error: cannot convert scoped(int*) to int*
	}

There is an interesting subtlety here, in that local variables
themselves are not necessarily scoped, for example:

	class C {}
	C createObj() {
		auto obj = new C;	// obj is a local variable
		return obj;		// but its lifetime can be extended outside the function
	}

Yet addresses of local variables are scoped:

	class C {}
	C* createObj() {
		auto obj = new C;
		return &obj;	// INVALID: this would allow the caller
				// to access a local variable that's
				// gone out of scope
	}

This leads to some further complications, for example:

	class C {
		C* getRef() { return &this; }
	}
	C* func(scope C obj) {
		// In here, obj's lifetime is the body of func

		// But this violates obj's lifetime:
		return obj.getRef();
	}

The problem is, how do we statically prevent this sort of abuse? since
the definition of C.getRef may not know anything about func, and so
can't possibly return a type whose lifetime is restricted to func, yet
that's what's needed to prevent the invalid return of obj.getRef's value
outside func.


> If it _cannot_ be inferred (even if imperfectly), then I wonder if it
> doesn't make more sense to invert the proposed default and require
> annotation when scope restrictions need to be eased.

The way I see it, scope is really a way for a function to state that it
won't keep a persistent reference to the scoped parameter, and so it's
OK to pass in, say, a reference to a temporary that will disappear after
the function returns. Defaulting to scope will cause far too much
breakage, I think, esp. given that code like the following is probably
common in the wild:

	class C {}
	C myFunc(C obj) {
		obj.doSomething();
		return obj; // will be rejected if parameters are scoped by default
	}


T

-- 
One disk to rule them all, One disk to find them. One disk to bring them all and in the darkness grind them. In the Land of Redmond where the shadows lie. -- The Silicon Valley Tarot


More information about the Digitalmars-d mailing list