www.digitalmars.com         C & C++   DMDScript  

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

reply "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
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:

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
Jul 10 2014
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 10/07/14 20:15, H. S. Teoh via Digitalmars-d wrote:

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

Hmm, why wouldn't that work? The scope where you called "myFunc" is guaranteed to outlive "myFunc". -- /Jacob Carlborg
Jul 10 2014
parent reply Jacob Carlborg <doob me.com> writes:
On 2014-07-11 16:29, H. S. Teoh via Digitalmars-d wrote:

 Because the scope of the parameter 'obj' is defined to be the scope of
 myFunc only, according to the current proposal.

Wouldn't it be possible to define the scope of a parameter to the caller's scope? -- /Jacob Carlborg
Jul 13 2014
parent reply Jacob Carlborg <doob me.com> writes:
On 13/07/14 16:37, H. S. Teoh via Digitalmars-d wrote:

 We could, but how would that help static analysis within the function's
 body, since the caller's scope is unknown?

Won't the caller's scope always outlive the callee's? -- /Jacob Carlborg
Jul 14 2014
parent reply Jacob Carlborg <doob me.com> writes:
On 15/07/14 01:48, H. S. Teoh via Digitalmars-d wrote:

 Yes, but since the extent of this scope is unknown from inside the
 function body, it doesn't easily lend itself nicely to check things like
 this:

 	int* ptr;
 	void func(scope int* arg) {
 		ptr = arg; // should this be allowed?
 	}

 If we only know that 'arg' has a longer lifetime than func, but we don't
 know how long it is, then we don't know if it has the same lifetime as
 'ptr', or less. So it doesn't really let us do useful checks.

I was thinking that "arg" would have at least the same lifetime as the caller, i.e. the same as "ptr". -- /Jacob Carlborg
Jul 15 2014
parent Jacob Carlborg <doob me.com> writes:
On 2014-07-15 16:58, H. S. Teoh via Digitalmars-d wrote:

 But what if 'ptr' is declared in a private binary-only module, and only
 the signature of 'func' is known? Then what should 'scope' mean to the
 compiler when 'func' is being called from another module?

Hmm, I didn't think of that :( -- /Jacob Carlborg
Jul 15 2014
prev sibling next sibling parent "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Fri, Jul 11, 2014 at 08:56:10AM +0200, Jacob Carlborg via Digitalmars-d
wrote:
 On 10/07/14 20:15, H. S. Teoh via Digitalmars-d wrote:
 
	class C {}
	C myFunc(C obj) {
		obj.doSomething();
		return obj; // will be rejected if parameters are scoped by default
	}

Hmm, why wouldn't that work? The scope where you called "myFunc" is guaranteed to outlive "myFunc".

Because the scope of the parameter 'obj' is defined to be the scope of myFunc only, according to the current proposal. T -- What are you when you run out of Monet? Baroque.
Jul 11 2014
prev sibling next sibling parent "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Sun, Jul 13, 2014 at 12:07:58PM +0200, Jacob Carlborg via Digitalmars-d
wrote:
 On 2014-07-11 16:29, H. S. Teoh via Digitalmars-d wrote:
 
Because the scope of the parameter 'obj' is defined to be the scope
of myFunc only, according to the current proposal.

Wouldn't it be possible to define the scope of a parameter to the caller's scope?

We could, but how would that help static analysis within the function's body, since the caller's scope is unknown? T -- Truth, Sir, is a cow which will give [skeptics] no more milk, and so they are gone to milk the bull. -- Sam. Johnson
Jul 13 2014
prev sibling next sibling parent "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Mon, Jul 14, 2014 at 10:41:10AM +0200, Jacob Carlborg via Digitalmars-d
wrote:
 On 13/07/14 16:37, H. S. Teoh via Digitalmars-d wrote:
 
We could, but how would that help static analysis within the
function's body, since the caller's scope is unknown?

Won't the caller's scope always outlive the callee's?

Yes, but since the extent of this scope is unknown from inside the function body, it doesn't easily lend itself nicely to check things like this: int* ptr; void func(scope int* arg) { ptr = arg; // should this be allowed? } If we only know that 'arg' has a longer lifetime than func, but we don't know how long it is, then we don't know if it has the same lifetime as 'ptr', or less. So it doesn't really let us do useful checks. T -- "I suspect the best way to deal with procrastination is to put off the procrastination itself until later. I've been meaning to try this, but haven't gotten around to it yet. " -- swr
Jul 14 2014
prev sibling parent "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Tue, Jul 15, 2014 at 09:19:34AM +0200, Jacob Carlborg via Digitalmars-d
wrote:
 On 15/07/14 01:48, H. S. Teoh via Digitalmars-d wrote:
 
Yes, but since the extent of this scope is unknown from inside the
function body, it doesn't easily lend itself nicely to check things
like this:

	int* ptr;
	void func(scope int* arg) {
		ptr = arg; // should this be allowed?
	}

If we only know that 'arg' has a longer lifetime than func, but we
don't know how long it is, then we don't know if it has the same
lifetime as 'ptr', or less. So it doesn't really let us do useful
checks.

I was thinking that "arg" would have at least the same lifetime as the caller, i.e. the same as "ptr".

But what if 'ptr' is declared in a private binary-only module, and only the signature of 'func' is known? Then what should 'scope' mean to the compiler when 'func' is being called from another module? T -- ASCII stupid question, getty stupid ANSI.
Jul 15 2014