December 07, 2014
On Saturday, 6 December 2014 at 12:38:24 UTC, Ola Fosheim Grøstad wrote:
> On Saturday, 6 December 2014 at 04:31:48 UTC, Sebastiaan Koppe wrote:
>> What about also adding the inverse of scope? Then scope can be inferred. As in:
>>
>> ```
>> void foo(int* p);
>> void free(P)(consume P* p);
>
>
> Yes, this is much better. When I suggested it, it was rejected because D is too concerned about breaking existing code. Which is a not-very-good argument since this breaking change is concervative (you only have to add "consume" or something similar when the compiler complains).
Hmm, I see.

Whenever I suggest to break something at my job - which, admittedly is much easier there than in a language - I get faced with some serious reluctance. My argument is always the same: It is going to make you happy, eventually.

How would it break anything though? Wouldn't functions eligible for `consume` already have the programmer ensuring the arguments haven't escaped before/after the function call? In case they did a bad job - sure it would break - but it would have been a bug.
>
> The obvious solution is to do as you suggest and in addition do all @safe analysis on a high level IR layer using dataflow through and through.
I am a big proponent of dataflow analyses, but I got the feeling people think is it pretty hard. Couldn't find much detailed papers on it, so I don't know.
December 07, 2014
On Sunday, 7 December 2014 at 06:52:38 UTC, Sebastiaan Koppe wrote:
> On Saturday, 6 December 2014 at 12:38:24 UTC, Ola Fosheim Grøstad wrote:
>> On Saturday, 6 December 2014 at 04:31:48 UTC, Sebastiaan Koppe wrote:

> I am a big proponent of dataflow analyses, but I got the feeling people think is it pretty hard.

I think D is in a good position to use the information available in assert* and in contracts for that.

Other languages have to use dedicated tools for that.

In a latter step, D could even formalize this into, as discussed in other threads, VRP sub-language. But, for the time being, the leverage offered by assert and in /out is available there to be used.


*yes, I know the war between assert and assume
December 07, 2014
On 2014-12-07 01:49, Manu via Digitalmars-d wrote:

> I have std.simd sitting here, and I really want to finish it, but I
> still don't have the tools to do so.
> I need, at least, forceinline to complete it, but that one *is*
> controversial - we've talked about this for years.
>
> GDC and LDC both have a forceinline, so I could theoretically support
> those compilers, but then I can't practically make use of them without
> some sort of attribute aliasing system, otherwise I need to triplicate
> the code for each compiler, just to insert a different (compiler
> specific) forceinline attribute name. It'd be really great if we
> agreed on just one.

I don't know about LDC but at least GDC allows you to use UDA's instead of a pragma. Then you can create a dummy attribute for DMD (and LDC):

version (GNU)
    import gcc.attribute

else
{
    struct attribute
    {
        string attr;
    }
}

@attribute("forceinline") void foo ();

-- 
/Jacob Carlborg
December 07, 2014
On Friday, 5 December 2014 at 23:58:41 UTC, Walter Bright wrote:
> On 12/5/2014 8:48 AM, "Marc Schütz" <schuetzm@gmx.net>" wrote:
>>     scope ref int foo();
>>     scope ref int bar1(ref int a) {
>>         return a;
>>     }
>>     scope ref int bar2(scope ref int a) {
>>         return a;
>>     }
>>     ref int bar3(ref int a) {
>>         return a;
>>     }
>>     ref int bar4(scope ref int a) {
>>         return a;
>>     }
>>     void baz(scope ref int a);
>>
>> Which of the following calls would work?
>>
>>     foo().bar1().baz();
>
> yes
>
>>     foo().bar2().baz();
>
> no - cannot return scope ref parameter
>
>>     foo().bar3().baz();
>
> yes
>
>>     foo().bar4().baz();
>
> no, cannot return scope ref parameter

I understand that scope will not allow the contents of the variable to escape the lifetime of a declaration. But can you explain why bar1() works, but bar2() doesn't? Isn't the body of bar2() in the line `foo().bar2();` part of the declaration?

Besides, what does it mean to return a `scope ref int`? Does it mean that the content of the variable that is returned is not allowed to escape the scope of the calling site? Huh?

It seemed so easy when you gave the example.

On Friday, 5 December 2014 at 20:55:55 UTC, Walter Bright wrote:
> It means that this code will be safe:
>
>    void foo(scope int* p);
>
>    p = malloc(n);
>    foo(p);
>    free(p);
>
> The rest is all the nuts and bolts of making that work.
December 07, 2014
On 7 Dec 2014 10:40, "Jacob Carlborg via Digitalmars-d" < digitalmars-d@puremagic.com> wrote:
>
> On 2014-12-07 01:49, Manu via Digitalmars-d wrote:
>
>> I have std.simd sitting here, and I really want to finish it, but I
>> still don't have the tools to do so.
>> I need, at least, forceinline to complete it, but that one *is*
>> controversial - we've talked about this for years.
>>
>> GDC and LDC both have a forceinline, so I could theoretically support those compilers, but then I can't practically make use of them without some sort of attribute aliasing system, otherwise I need to triplicate the code for each compiler, just to insert a different (compiler specific) forceinline attribute name. It'd be really great if we agreed on just one.
>
>
> I don't know about LDC but at least GDC allows you to use UDA's instead
of a pragma. Then you can create a dummy attribute for DMD (and LDC):
>
> version (GNU)
>     import gcc.attribute
>
> else
> {
>     struct attribute
>     {
>         string attr;
>     }
> }
>
> @attribute("forceinline") void foo ();
>

You can add shorthand aliases for them too. :)

@forceinline void foo ();


December 07, 2014
On Sunday, 7 December 2014 at 06:52:38 UTC, Sebastiaan Koppe wrote:
> How would it break anything though? Wouldn't functions eligible for `consume` already have the programmer ensuring the arguments haven't escaped before/after the function call? In case they did a bad job - sure it would break - but it would have been a bug.

I don't think the breakage is a serious problem in this case, so I obviously agree with you…

But, the deep-rooted problem is that you actually need different properties associated with  pointers to do this properly: unique, single-threaded shared, multi-threaded shared, gc, non-owning… And this could be resolved with templates and having the compiler recognize pointer resolutions that lead to the same lower level code (to avoid bloat). But the D authors don't want ownership related pointertypes… and I can't see that work.

> I am a big proponent of dataflow analyses, but I got the feeling people think is it pretty hard. Couldn't find much detailed papers on it, so I don't know.

You can do it in a simpler and conservative fashion and accept false positives (or negatives) so that you here-and-there have to inject annotations like this: "trust me I have proven that this property holds here", then let the compiler infer the rest.

With a good IDE this should be no biggie: just inject suggestions in the code and let the programmer confirm/refine them.

If you want to guarantee memory-safety you should do it with a single uniform mechanism, trying to do it bit-by-bit special casing is not a good idea. So given the current approach, I'm inclined to turn off @safe, make everything @nogc, write my own libraries with unique_ptr/shared_ptr and call it a day… The current approach does not address situations where I run into memory related bugs in my own code.
December 07, 2014
On Thursday, 4 December 2014 at 09:25:11 UTC, Walter Bright wrote:
> http://wiki.dlang.org/DIP69
>
> Despite its length, this is a fairly simple proposal. It adds the missing semantics for the 'scope' storage class in order to make it possible to pass a reference to a function without it being possible for it to escape.
>
> This, among other things, makes a ref counting type practical. It also makes it more practical to use other storage allocation schemes than garbage collection.
>
> It does not make scope into a type constructor, nor a general type-annotation system.
>
> It does not provide an ownership system, though it would complement one.

Thanks a lot of trying to move forward with this. Also glad to see DIP36 didn't vanish completely useless :P It will take me some time to provide a detailed response so I'll post a summary of my impression first.

I recognize and respect your attempt to go for most simple solution that is still useful in practice. Can't say I am happy about it but it is better to have something working than awesome plans that never get implemented. In this context trying to get most of scope as storage class seems right.

But from existing cases it doesn't seem working good enough. For example, not being able to represent idiom of `scope ref int foo(scope ref int x) { return x; }` seems very limiting. There are also issues that pop up because of missing transitivity. Maybe this can be fixed within existing proposal, maybe not. Right now I don't have any strong opinion.

I also don't consider `ref` design as a storage class any kind of success at all and generally agree with Manu on this topic. At the same time alternative proposals that make it a qualifier (like Marc did) do impact existing language much more and this no small concern.

This won't be easy.
December 07, 2014
On 2014-12-07 11:50, Iain Buclaw via Digitalmars-d wrote:

> You can add shorthand aliases for them too. :)
>
> @forceinline void foo ();

Good point.

-- 
/Jacob Carlborg
December 07, 2014
On 05/12/2014 23:58, Walter Bright wrote:
>> 2) `scope ref` return values cannot be stored.
>>
>>      scope ref int foo();
>>      void bar(scope ref int a);
>>
>>      foo().bar();        // allowed
>>      scope tmp = foo();  // not allowed
>>      tmp.bar();
>
> Right

From the DIP:

"The lifetime of a scope return value is the lifetime of an rvalue. It may not be copied in a way that extends its life."

With part of the example:

scope int* foo();
...
int* p = foo();       // Error, lifetime(p) is &infin;

Maybe the error should be 'scope return value cannot be stored', because otherwise p could be inferred as scope.
December 07, 2014
On 04/12/2014 12:55, bearophile wrote:
> Regarding array literals, some people proposed a syntax for fixed-size
> arrays to avoid heap-allocations (the "s" after the array literal):
>
> void foo(int[2]) {}
> void bar(scope int[]) {}
> void main() @nogc {
>      foo([1, 2]s);
>      bar([1, 2]s);
> }

I think even if the compiler could infer them as static arrays, it may still be useful to be explicit sometimes. We can already use a library template:

template staticArray(items...)
{
    import std.traits;
    alias T = CommonType!items[items.length];
    enum T staticArray = [items];
}

auto s = staticArray!(1, 2);
static assert(is(typeof(s) == int[2]));

bar(staticArray!(1, 2));

This might also make the proposed 'int[$] = [...];' syntax unnecessary.

I think jmdavis once wrote something similar - although I've used enum here in case it helps avoid function template bloat.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19