September 11, 2014
On Thursday, 11 September 2014 at 16:32:54 UTC, Ivan Timokhin wrote:
> I am in no way a language guru, but here are a few things that bother me in your proposal. Thought I'd share.

Neither am I :-)

>
> 1. AFAIK, all current D type modifiers can be safely removed from the topmost level (i.e. it is OK to assign immutable(int[]) to immutable(int)[]), because they currently apply to particular variable, so there's no good reason to impose same restrictions on its copy. Situation seems different with scope: it is absolutely not safe to cast away and it applies to a *value*, not a variable holding it.

The types in your example are implicitly convertable, indeed no explicit cast is necessary. This is because when you copy a const value, the result doesn't need to be const. But with scope, it makes sense (and is of course necessary) to keep the ownership. I don't see that as an inconsistency, but as a consequence of the different things const and scope imply: mutability vs. ownership.

>
> This is not only inconsistent, but may also cause trouble with interaction with existing features. For example, what should be std.traits.Unqual!(scope(int*)) ?

Good question. I would say it needs to keep scope, as it was clearly designed with mutability in mind (although it also removes shared, which is however related to mutability in a way). Ownership is an orthogonal concept to mutability.

>
> 2. Consider findSubstring from your examples. What should be typeof(findSubstring("", ""))? Is the following code legal?
>
> 	scope(string) a = ..., b = ...;
> 	...
> 	typeof(findSubstring("", "")) c = findSubstring(a, b);
>

It's not legal. String literals live forever, so `c` has an owner that lives longer than `a` and `b`.

An alternative interpretation would be that the literals are temporary expressions; then it would have a very short lifetime, thus the assignment would be accepted. But I guess there needs to be a rule that says that the specified owners must not live shorter than the variable itself.

> This is a bit troublesome, because this is how things like std.range.ElementType work currently, so they may break. For example,
> what would be ElementType!ByLineImpl (from the "scope(const...)" section)?

I see... it can _not_ be:

    scope!(const ByLineImpl!(char, "\n").init)(ByLineImpl!(char, "\n"))

because the init value is copied and thus becomes a temporary. This is ugly. It would however work if ElementType would take an instance instead of a type.

>
> This troubles me the most, because currently return type of a function may depend only on types of its arguments, and there is a lot of templated code written in that assumption.

I'm sorry, I don't understand what you mean here. This is clearly not true, neither for normal functions, nor for templates.

> With the current proposal it ALL could break. Maybe there's no way around it if we want a solid lifetime management system, but I think this is definitely a problem to be aware of.

The answer may be that scope needs to be something independent from the type, indeed more like a storage class, rather than what I suggested a type modifier. This would also solve the problem about `std.traits.Unqual`, no?

I'd have to think this through, but I believe this is indeed the way to go. It would make several other things cleaner. On the other hand, it would then be impossible to have scoped member fields, because storage classes aren't usable there, AFAIK. This would need to be supported first.

>
> 3. I believe it was mentioned before, but shouldn't scope propagate *outwards*? This would not only make perfect sense, since the aggregate obviously "holds the reference" just as well as its member does, it would also make various range-wrappers and alike automatically scope-aware, in that the wrapper would automatically become scoped if the wrapped range is scoped.

You mean that any aggregate that contains a member with owner X automatically gets X as its owner itself?

I don't think so, because assigning a struct is semantically equivalent to assigning its members individually one after the others (by default) or whatever opAssign() is implemented to do. This means that an assignment that violates the rules would fail anyway, because the ownership is codified as part of the member's type. Instances of wrapper types would also need to be declared as scope with the appropriate owner, because otherwise they could not contain the scoped variables.

But I'm not sure how this is supposed to work with the storage class version of scope.
September 12, 2014
On Thursday, 11 September 2014 at 20:45:09 UTC, Marc Schütz wrote:
> On Thursday, 11 September 2014 at 16:32:54 UTC, Ivan Timokhin wrote:
>> 1. AFAIK, all current D type modifiers can be safely removed from the topmost level (i.e. it is OK to assign immutable(int[]) to immutable(int)[]), because they currently apply to particular variable, so there's no good reason to impose same restrictions on its copy. Situation seems different with scope: it is absolutely not safe to cast away and it applies to a *value*, not a variable holding it.
>
> The types in your example are implicitly convertable, indeed no explicit cast is necessary. This is because when you copy a const value, the result doesn't need to be const. But with scope, it makes sense (and is of course necessary) to keep the ownership. I don't see that as an inconsistency, but as a consequence of the different things const and scope imply: mutability vs. ownership.

I've addressed this in the Wiki now. There were only a few changes to be made to move away from type modifiers. I had even suggested it as an implementation detail, but didn't think of making it part of the specification. Thank you for that insight, it makes the proposal more consistent and avoids the troubles with the types.

>
>>
>> This is not only inconsistent, but may also cause trouble with interaction with existing features. For example, what should be std.traits.Unqual!(scope(int*)) ?
>
> Good question. I would say it needs to keep scope, as it was clearly designed with mutability in mind (although it also removes shared, which is however related to mutability in a way). Ownership is an orthogonal concept to mutability.

After the changes, this is now the case.

>> This is a bit troublesome, because this is how things like std.range.ElementType work currently, so they may break. For example,
>> what would be ElementType!ByLineImpl (from the "scope(const...)" section)?
>
> I see... it can _not_ be:
>
>     scope!(const ByLineImpl!(char, "\n").init)(ByLineImpl!(char, "\n"))
>
> because the init value is copied and thus becomes a temporary. This is ugly. It would however work if ElementType would take an instance instead of a type.

Ditto, this works now. The type is now simply `char[]` (or whatever), the owner is tracked separately.
September 12, 2014
11.09.2014 22:45, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm@gmx.net>" пишет:
>...
>>
>> This troubles me the most, because currently return type of a function
>> may depend only on types of its arguments, and there is a lot of
>> templated code written in that assumption.
>
> I'm sorry, I don't understand what you mean here. This is clearly not
> true, neither for normal functions, nor for templates.

Well, me and my bad English. I was trying to say that currently, AFAIK,
for any symbols f, a, b, if f(a) is valid and the types of a and b match, then f(b) is also valid and types of f(a) and f(b) match. OTOH, if the types of a and b are different, types of f(a) and f(b) may also be different (because of overloading or templates like T f(T)(T x)).

This would change if scope became a type qualifier and f was something like scope!x(T) f(T)(scope(T) x).

>...
September 13, 2014
On 12 September 2014 18:06, via Digitalmars-d <digitalmars-d@puremagic.com> wrote:

> On Thursday, 11 September 2014 at 20:45:09 UTC, Marc Schütz wrote:
>
>> On Thursday, 11 September 2014 at 16:32:54 UTC, Ivan Timokhin wrote:
>>
>>> 1. AFAIK, all current D type modifiers can be safely removed from the topmost level (i.e. it is OK to assign immutable(int[]) to immutable(int)[]), because they currently apply to particular variable, so there's no good reason to impose same restrictions on its copy. Situation seems different with scope: it is absolutely not safe to cast away and it applies to a *value*, not a variable holding it.
>>>
>>
>> The types in your example are implicitly convertable, indeed no explicit cast is necessary. This is because when you copy a const value, the result doesn't need to be const. But with scope, it makes sense (and is of course necessary) to keep the ownership. I don't see that as an inconsistency, but as a consequence of the different things const and scope imply: mutability vs. ownership.
>>
>
> I've addressed this in the Wiki now. There were only a few changes to be made to move away from type modifiers. I had even suggested it as an implementation detail, but didn't think of making it part of the specification. Thank you for that insight, it makes the proposal more consistent and avoids the troubles with the types.


I'm not convinced this is a good change.
It sounds like you're just trading one problem with another more sinister
problem...

What happens when a scope() thing finds it's way into generic code? If the
type doesn't carry that information, then you end up in a situation like
ref. Have you ever had to wrestle with ref in generic code?
ref is the biggest disaster zone in D, and I think all it's problems will
translate straight to scope if you do this.


This is not only inconsistent, but may also cause trouble with interaction
>>> with existing features. For example, what should be
>>> std.traits.Unqual!(scope(int*)) ?
>>>
>>
>> Good question. I would say it needs to keep scope, as it was clearly designed with mutability in mind (although it also removes shared, which is however related to mutability in a way). Ownership is an orthogonal concept to mutability.
>>
>
> After the changes, this is now the case.
>
>  This is a bit troublesome, because this is how things like
>>> std.range.ElementType work currently, so they may break. For example,
>>> what would be ElementType!ByLineImpl (from the "scope(const...)"
>>> section)?
>>>
>>
>> I see... it can _not_ be:
>>
>>     scope!(const ByLineImpl!(char, "\n").init)(ByLineImpl!(char, "\n"))
>>
>> because the init value is copied and thus becomes a temporary. This is ugly. It would however work if ElementType would take an instance instead of a type.
>>
>
> Ditto, this works now. The type is now simply `char[]` (or whatever), the owner is tracked separately.
>


September 13, 2014
On Saturday, 13 September 2014 at 01:49:05 UTC, Manu via Digitalmars-d wrote:
> On 12 September 2014 18:06, via Digitalmars-d <digitalmars-d@puremagic.com>
> wrote:
>
>> On Thursday, 11 September 2014 at 20:45:09 UTC, Marc Schütz wrote:
>> I've addressed this in the Wiki now. There were only a few changes to be
>> made to move away from type modifiers. I had even suggested it as an
>> implementation detail, but didn't think of making it part of the
>> specification. Thank you for that insight, it makes the proposal more
>> consistent and avoids the troubles with the types.
>
>
> I'm not convinced this is a good change.
> It sounds like you're just trading one problem with another more sinister
> problem...
>
> What happens when a scope() thing finds it's way into generic code? If the
> type doesn't carry that information, then you end up in a situation like
> ref. Have you ever had to wrestle with ref in generic code?
> ref is the biggest disaster zone in D, and I think all it's problems will
> translate straight to scope if you do this.

Could you give an example?
September 19, 2014
PING again

On Thursday, 11 September 2014 at 13:58:40 UTC, Marc Schütz wrote:
> PING
>
> Now that there are again several GC related topics being discussed, I thought I'd bump this thread.
>
> Would be nice if Walter and/or Andrei could have a look and share there opinions. Is this something worth pursuing further? Are there fundamental objections against it?
>
> On Sunday, 24 August 2014 at 13:14:45 UTC, Marc Schütz wrote:
>> In the "Opportunities for D" thread, Walter again mentioned the topics ref counting, GC, uniqueness, and borrowing, from which a lively discussion developed [1]. I took this thread as an opportunity to write down some ideas about these topics. The result is a rather extensive proposal for the implementation of borrowing, and its implementations:
>>
>> http://wiki.dlang.org/User:Schuetzm/scope
>>
>> This is not a real DIP, but before I put more work into formalizing it, I'd like to hear some thoughts from the languages gurus here:
>>
>> * Is this the general direction we want to go? Is it acceptable in general?
>> * Is the proposal internally consistent?
>> * How big would the effort to implement it be? (I suspect it's a large amount of work, but relatively straightforward.)
>>
>> [1] http://forum.dlang.org/thread/lphnen$1ml7$1@digitalmars.com

September 19, 2014
On 9/19/14, 4:34 AM, "Marc Schütz" <schuetzm@gmx.net>" wrote:
> PING again

Thanks for your work. I've put it on my todo list. -- Andrei

September 21, 2014
Previous discussions:

http://www.digitalmars.com/d/archives/digitalmars/D/borrowed_pointers_vs_ref_232090.html

http://www.digitalmars.com/d/archives/digitalmars/D/RFC_scope_and_borrowing_240834.html

http://www.digitalmars.com/d/archives/digitalmars/D/scope_escaping_222858.html

http://www.digitalmars.com/d/archives/digitalmars/D/ref_is_unsafe_184935.html
September 21, 2014
On Sunday, 21 September 2014 at 01:28:19 UTC, Walter Bright wrote:
> Previous discussions:

Forum links:

http://forum.dlang.org/?group=digitalmars.D&artnum=232090
http://forum.dlang.org/?group=digitalmars.D&artnum=240834
http://forum.dlang.org/?group=digitalmars.D&artnum=222858	
http://forum.dlang.org/?group=digitalmars.D&artnum=184935
September 21, 2014
I think it's a well thought out proposal. Thanks for doing this!

A couple thoughts:

1. const can be both a storage class and a type constructor. Scope is only a storage class. The scope(int) syntax implies scope is a type constructor, too.

    const int* a;  // const used as storage class
    const(int*) b; // const used as type constructor

The type constructor syntax should be disallowed for const.


2. I think there is quite a bit of overlap between scope and ref. Essentially, ref does everything scope does, except deal with classes. I'm not terribly comfortable with such a large overlap, it implies something is wrong. I don't have an answer at the moment.