November 17, 2011
On 17 November 2011 09:03, Jonathan M Davis <jmdavisProg at gmx.com> wrote:
> On Thursday, November 17, 2011 07:51:24 Rainer Schuetze wrote:
>> On 16.11.2011 15:35, Steve Schveighoffer wrote:
>> > Take this argument with a grain of salt, I have very little internal dmd knowledge. ?But...
>> >
>> > Isn't deduction of pure/nothrow/safe restricted to templates? ?Don't templates *require* availability of source?
>> >
>> > Just saying...
>> >
>> > -Steve
>>
>> I think it would be an unexpected restricton to limit pure/nothrow/safe inference to templates. But if it is not, using di files instead of d files will break code because inference very much depends on whether the di-file generation emitted the code or not. Adding inferred attributes to ?the function declarations could help but it currently changes the name mangling, breaking it again.
>
> It's _already_ restricted to templates and delegates. You _need_ it for templates, since whether they can be pure, nothrow, or @safe depends on their arguments, and the only way to do that without inference is to duplicate the template a bunch of times with each possible combination of pur,e nothrow, and @safe. Normal functions, however, do _not_ need the inference. Whether they can be pure, nothrow, or @safe doesn't change unless you change according to their arguments.
>
> In any case, I don't quite understand how this is an issue, since as Steve says, templates _require_ that their source be available.

Inference doesn't apply only to templates. It applies also to delegate/function literals, and to function pointers.
November 17, 2011
Withdraw a previous statement, I still argue that is better to apply
result of inference into mangleof.
First of all, the pure/safe/nothrow inference runs against only
function literals and template functions.For function literal, its
type determines in the place its written.For template function, its
type determines in its instantiation.Both of cases can always see
their function bodies. Then the problem that Don said never comes.
And second, see following description of an issue that I found.
alias typeof({}) D;static if (is(typeof({}) X == delegate)) alias X
F;pragma(msg, F.mangleof);	// (1)pragma(msg, D.mangleof);	// (2)
In dmd2.057head, #1 prints "FZv", and #2 prints "DFNaNbNfZv"It is
definitely inconsistent.(From this fact, I was convinced that
separating inference result from the type is much difficult.)
Do you think it should do? If we select the conservative strategy,
that Don and Walter agree, D.mangleof should return "DFZv".But, the
decision will break existing codes, like std.exception.enforce.
T enforce(T, Dg : void delegate())(T, scope Dg dg){ ... }
Now this template function supports pure/safe/nothrow attributes that
depends on the Dg type.But the conservative decision will make the
deduction result of Dg in the following calling,
enforce(condtion, { ; })
as which the type of delegate literal is 'void delegate()' because the
type inference does not apply into type.And we'll never use enforce in
pure/nothrow/safe function with delegate literal argument.
As the end of second, F.mangleof should return "FNaNbNfZv", and
D.mangleof should return "DFNaNbNfZv".
>From the above description, I think that applying the inference result
into "mangleof" property (and the type) is the best way.
Kenji Hara

2011/11/17 Don Clugston <dclugston at googlemail.com>:
> On 17 November 2011 09:03, Jonathan M Davis <jmdavisProg at gmx.com> wrote:
>> On Thursday, November 17, 2011 07:51:24 Rainer Schuetze wrote:
>>> On 16.11.2011 15:35, Steve Schveighoffer wrote:
>>> > Take this argument with a grain of salt, I have very little internal dmd knowledge. ?But...
>>> >
>>> > Isn't deduction of pure/nothrow/safe restricted to templates? ?Don't templates *require* availability of source?
>>> >
>>> > Just saying...
>>> >
>>> > -Steve
>>>
>>> I think it would be an unexpected restricton to limit pure/nothrow/safe inference to templates. But if it is not, using di files instead of d files will break code because inference very much depends on whether the di-file generation emitted the code or not. Adding inferred attributes to ?the function declarations could help but it currently changes the name mangling, breaking it again.
>>
>> It's _already_ restricted to templates and delegates. You _need_ it for templates, since whether they can be pure, nothrow, or @safe depends on their arguments, and the only way to do that without inference is to duplicate the template a bunch of times with each possible combination of pur,e nothrow, and @safe. Normal functions, however, do _not_ need the inference. Whether they can be pure, nothrow, or @safe doesn't change unless you change according to their arguments.
>>
>> In any case, I don't quite understand how this is an issue, since as Steve says, templates _require_ that their source be available.
>
> Inference doesn't apply only to templates. It applies also to
> delegate/function literals, and to function pointers.
> _______________________________________________
> dmd-internals mailing list
> dmd-internals at puremagic.com
> http://lists.puremagic.com/mailman/listinfo/dmd-internals
>
November 17, 2011
Withdraw a previous statement, I still argue that is better to apply result of inference into mangleof.

First of all, the pure/safe/nothrow inference runs against only
function literals and template functions.
For function literal, its type determines in the place its written.
For template function, its type determines in its instantiation.
Both of cases can always see their function bodies. Then the problem
that Don said never comes.

And second, see following description of an issue that I found.

alias typeof({}) D;
static if (is(typeof({}) X == delegate)) alias X F;
pragma(msg, F.mangleof);    // (1)
pragma(msg, D.mangleof);    // (2)

In dmd2.057head, #1 prints "FZv", and #2 prints "DFNaNbNfZv"
It is definitely inconsistent.
(From this fact, I was convinced that separating inference result from
the type is much difficult.)

Do you think it should do? If we select the conservative strategy,
that Don and Walter agree, D.mangleof should return "DFZv".
But, the decision will break existing codes, like std.exception.enforce.

T enforce(T, Dg : void delegate())(T, scope Dg dg){ ... }

Now this template function supports pure/safe/nothrow attributes that
depends on the Dg type.
But the conservative decision will make the deduction result of Dg in
the following calling,

enforce(condtion, { ; });

as which the type of delegate literal is 'void delegate()' because the
type inference does not apply into type.
And we'll never use enforce in pure/nothrow/safe function with
delegate literal argument.

As the end of second, F.mangleof should return "FNaNbNfZv", and D.mangleof should return "DFNaNbNfZv".

>From the above description, I think that applying the inference result
into "mangleof" property (and the type) is the best way.

Kenji Hara

2011/11/17 kenji hara <k.hara.pg at gmail.com>:> Withdraw a previous statement, I still argue that is better to apply
> result of inference into mangleof.
> First of all, the pure/safe/nothrow inference runs against only
> function literals and template functions.For function literal, its
> type determines in the place its written.For template function, its
> type determines in its instantiation.Both of cases can always see
> their function bodies. Then the problem that Don said never comes.
> And second, see following description of an issue that I found.
> alias typeof({}) D;static if (is(typeof({}) X == delegate)) alias X
> F;pragma(msg, F.mangleof); ? ? ?// (1)pragma(msg, D.mangleof); ?// (2)
> In dmd2.057head, #1 prints "FZv", and #2 prints "DFNaNbNfZv"It is
> definitely inconsistent.(From this fact, I was convinced that
> separating inference result from the type is much difficult.)
> Do you think it should do? If we select the conservative strategy,
> that Don and Walter agree, D.mangleof should return "DFZv".But, the
> decision will break existing codes, like std.exception.enforce.
> T enforce(T, Dg : void delegate())(T, scope Dg dg){ ... }
> Now this template function supports pure/safe/nothrow attributes that
> depends on the Dg type.But the conservative decision will make the
> deduction result of Dg in the following calling,
> enforce(condtion, { ; })
> as which the type of delegate literal is 'void delegate()' because the
> type inference does not apply into type.And we'll never use enforce in
> pure/nothrow/safe function with delegate literal argument.
> As the end of second, F.mangleof should return "FNaNbNfZv", and
> D.mangleof should return "DFNaNbNfZv".
> From the above description, I think that applying the inference result
> into "mangleof" property (and the type) is the best way.
> Kenji Hara
>
> 2011/11/17 Don Clugston <dclugston at googlemail.com>:
>> On 17 November 2011 09:03, Jonathan M Davis <jmdavisProg at gmx.com> wrote:
>>> On Thursday, November 17, 2011 07:51:24 Rainer Schuetze wrote:
>>>> On 16.11.2011 15:35, Steve Schveighoffer wrote:
>>>> > Take this argument with a grain of salt, I have very little internal dmd knowledge. ?But...
>>>> >
>>>> > Isn't deduction of pure/nothrow/safe restricted to templates? ?Don't templates *require* availability of source?
>>>> >
>>>> > Just saying...
>>>> >
>>>> > -Steve
>>>>
>>>> I think it would be an unexpected restricton to limit pure/nothrow/safe inference to templates. But if it is not, using di files instead of d files will break code because inference very much depends on whether the di-file generation emitted the code or not. Adding inferred attributes to ?the function declarations could help but it currently changes the name mangling, breaking it again.
>>>
>>> It's _already_ restricted to templates and delegates. You _need_ it for templates, since whether they can be pure, nothrow, or @safe depends on their arguments, and the only way to do that without inference is to duplicate the template a bunch of times with each possible combination of pur,e nothrow, and @safe. Normal functions, however, do _not_ need the inference. Whether they can be pure, nothrow, or @safe doesn't change unless you change according to their arguments.
>>>
>>> In any case, I don't quite understand how this is an issue, since as Steve says, templates _require_ that their source be available.
>>
>> Inference doesn't apply only to templates. It applies also to
>> delegate/function literals, and to function pointers.
>> _______________________________________________
>> dmd-internals mailing list
>> dmd-internals at puremagic.com
>> http://lists.puremagic.com/mailman/listinfo/dmd-internals
>>
>
November 17, 2011
On 17 November 2011 11:09, kenji hara <k.hara.pg at gmail.com> wrote:
> Withdraw a previous statement, I still argue that is better to apply
> result of inference into mangleof.
> First of all, the pure/safe/nothrow inference runs against only
> function literals and template functions.

This is true at present. But are we confident that it will never apply to anything else?

> For function literal, its
> type determines in the place its written.For template function, its
> type determines in its instantiation.Both of cases can always see
> their function bodies.

Are we happy to say that when full type inference is used, it does NOT invoke safe/pure/nothrow inference?

immutable fptr = &foo!(7);
immutable fptr2 = (){ return 0; }

That is, both fptr and fptr2 will always be impure, @system, and throw? Or does it invoke safe/pure/nothrow inference? In which case the situation I mentioned arises.
November 17, 2011
Another interesting case:

// This is just a trick to get a delegate literal into an alias.
template XX(alias Z)
{
    alias Z XX;
}
alias XX!( (){ return 2; }) Q;

pragma(msg, Q.stringof);
pragma(msg, typeof(Q).stringof);
=================
__dgliteral1
int delegate() pure nothrow @safe

I can't see any reason for the delegate literal to be stored in the
.di file. Surely the compiler could legally just put __dgliteral1 in
it.
This whole thing is pretty nasty.


On 17 November 2011 12:01, Don Clugston <dclugston at googlemail.com> wrote:
> On 17 November 2011 11:09, kenji hara <k.hara.pg at gmail.com> wrote:
>> Withdraw a previous statement, I still argue that is better to apply
>> result of inference into mangleof.
>> First of all, the pure/safe/nothrow inference runs against only
>> function literals and template functions.
>
> This is true at present. But are we confident that it will never apply to anything else?
>
>> For function literal, its
>> type determines in the place its written.For template function, its
>> type determines in its instantiation.Both of cases can always see
>> their function bodies.
>
> Are we happy to say that when full type inference is used, it does NOT invoke safe/pure/nothrow inference?
>
> immutable fptr = &foo!(7);
> immutable fptr2 = (){ return 0; }
>
> That is, both fptr and fptr2 will always be impure, @system, and throw? Or does it invoke safe/pure/nothrow inference? In which case the situation I mentioned arises.
>
November 17, 2011
2011/11/17 Don Clugston <dclugston at googlemail.com>:
> On 17 November 2011 11:09, kenji hara <k.hara.pg at gmail.com> wrote:
>> Withdraw a previous statement, I still argue that is better to apply
>> result of inference into mangleof.
>> First of all, the pure/safe/nothrow inference runs against only
>> function literals and template functions.
>
> This is true at present. But are we confident that it will never apply to anything else?
>
>> For function literal, its
>> type determines in the place its written.For template function, its
>> type determines in its instantiation.Both of cases can always see
>> their function bodies.
>
> Are we happy to say that when full type inference is used, it does NOT invoke safe/pure/nothrow inference?

Template function instantiation and function literal type inference
always also invoke attribute inference.
They are inseparable.

> immutable fptr = &foo!(7);
> immutable fptr2 = (){ return 0; }
>
> That is, both fptr and fptr2 will always be impure, @system, and throw? Or does it invoke safe/pure/nothrow inference? In which case the situation I mentioned arises.

Maybe you are worried about breaking pure/safe/nothrow-ness silently,
but it does not happen.
Because AutoDeclaration always invoke the semantics of its
initializer, just for its type inference.
Then, in types of fptr and fptr2, function type attributes should
always be inferred based on their initializers.
(I know bug 6963, current dmd does not invoke attribute inference of
declaration in module level.)

Through semantic processing over the modules, types and attributes are always guaranteed.

Kenji Hara
November 17, 2011
On 17 November 2011 13:43, kenji hara <k.hara.pg at gmail.com> wrote:
> 2011/11/17 Don Clugston <dclugston at googlemail.com>:
>> On 17 November 2011 11:09, kenji hara <k.hara.pg at gmail.com> wrote:
>>> Withdraw a previous statement, I still argue that is better to apply
>>> result of inference into mangleof.
>>> First of all, the pure/safe/nothrow inference runs against only
>>> function literals and template functions.
>>
>> This is true at present. But are we confident that it will never apply to anything else?
>>
>>> For function literal, its
>>> type determines in the place its written.For template function, its
>>> type determines in its instantiation.Both of cases can always see
>>> their function bodies.
>>
>> Are we happy to say that when full type inference is used, it does NOT invoke safe/pure/nothrow inference?
>
> Template function instantiation and function literal type inference
> always also invoke attribute inference.
> They are inseparable.
>
>> immutable fptr = &foo!(7);
>> immutable fptr2 = (){ return 0; }
>>
>> That is, both fptr and fptr2 will always be impure, @system, and throw? Or does it invoke safe/pure/nothrow inference? In which case the situation I mentioned arises.
>
> Maybe you are worried about breaking pure/safe/nothrow-ness silently, but it does not happen.

No, I'm worried about noisy breaking of pure/nothrow. It can even go in the other direction. Delete a read from a static variable in the body of a template function (not the signature) and now your code won't link, because the function suddenly became pure. The issue is predictability.

Absence of an attribute means either  "impure" _or_ "don't know/don't care/please work it out for me". Somehow, we have to keep this ambiguity out of external interfaces. It's not much of a problem with safe, because we have the @system qualifier. But we have no @impure, @maythrow -- there is no way to say, "this is *intentionally* not pure, even if it's inferred as pure at the moment".

As Rainer says, it does seem odd to restrict purity inference to templates functions and delegate literals. It would not be at all difficult to implement it for functions as well. That would be nice, because then code wouldn't need to be littered with annotations. As far as I can tell, the only argument against doing it, is this unpredictability problem. Arguably, the inference for templates generates so much unpredicatibility, that we might as well extend it to functions.

Something I should clarify -- I'm just playing devil's advocate here, I don't actually have an opinion on what we should do.

> Because AutoDeclaration always invoke the semantics of its
> initializer, just for its type inference.
> Then, in types of fptr and fptr2, function type attributes should
> always be inferred based on their initializers.
> (I know bug 6963, current dmd does not invoke attribute inference of
> declaration in module level.)
>
> Through semantic processing over the modules, types and attributes are always guaranteed.
>
> Kenji Hara
> _______________________________________________
> dmd-internals mailing list
> dmd-internals at puremagic.com
> http://lists.puremagic.com/mailman/listinfo/dmd-internals
>
November 18, 2011
2011/11/17 Don Clugston <dclugston at googlemail.com>:
> On 17 November 2011 13:43, kenji hara <k.hara.pg at gmail.com> wrote:
>> 2011/11/17 Don Clugston <dclugston at googlemail.com>:
>>> On 17 November 2011 11:09, kenji hara <k.hara.pg at gmail.com> wrote:
>>>> Withdraw a previous statement, I still argue that is better to apply
>>>> result of inference into mangleof.
>>>> First of all, the pure/safe/nothrow inference runs against only
>>>> function literals and template functions.
>>>
>>> This is true at present. But are we confident that it will never apply to anything else?
>>>
>>>> For function literal, its
>>>> type determines in the place its written.For template function, its
>>>> type determines in its instantiation.Both of cases can always see
>>>> their function bodies.
>>>
>>> Are we happy to say that when full type inference is used, it does NOT invoke safe/pure/nothrow inference?
>>
>> Template function instantiation and function literal type inference
>> always also invoke attribute inference.
>> They are inseparable.
>>
>>> immutable fptr = &foo!(7);
>>> immutable fptr2 = (){ return 0; }
>>>
>>> That is, both fptr and fptr2 will always be impure, @system, and throw? Or does it invoke safe/pure/nothrow inference? In which case the situation I mentioned arises.
>>
>> Maybe you are worried about breaking pure/safe/nothrow-ness silently, but it does not happen.
>
> No, I'm worried about noisy breaking of pure/nothrow. It can even go in the other direction. Delete a read from a static variable in the body of a template function (not the signature) and now your code won't link, because the function suddenly became pure. The issue is predictability.
>
> Absence of an attribute means either ?"impure" _or_ "don't know/don't care/please work it out for me". Somehow, we have to keep this ambiguity out of external interfaces. It's not much of a problem with safe, because we have the @system qualifier. But we have no @impure, @maythrow -- there is no way to say, "this is *intentionally* not pure, even if it's inferred as pure at the moment".
>
> As Rainer says, it does seem odd to restrict purity inference to templates functions and delegate literals. It would not be at all difficult to implement it for functions as well. That would be nice, because then code wouldn't need to be littered with annotations. As far as I can tell, the only argument against doing it, is this unpredictability problem. Arguably, the inference for templates generates so much unpredicatibility, that we might as well extend it to functions.
>
> Something I should clarify -- I'm just playing devil's advocate here, I don't actually have an opinion on what we should do.

OK, I understand what you're worried.
But, conservative mangling of template function never rescue anything, IMO.
It just decrease the type information and cause inconsistent confusion.
See following example.

---- a.d
int g;
int foo(int n)() {
    version (impure) g = n;
    return n;
}
int call() {
    return foo!1();
    pragma(msg, "in a: ", typeof(&foo!1));
}

---- b.d
import a;
void main() {
    assert(a.call() == 1);
    assert(a.g == 0);   // Line4: should fail if you compile a.d with
-version=impure

    pragma(msg, "in b: ", typeof(&foo!1));
    assert(foo!1() == 1);
    assert(a.g == 0);   // Line8: should fail if you compile b,d with
-version=impure
}

---- cmd
$ dmd -c a.d
in a: int function() pure nothrow @safe
$ dmd -c b.d -version=impure
in b: int function() nothrow @safe
$ dmd -ofx -map a.obj b.obj
$ x
  <----- Merged foo!1() instantiation into pure version.

$ dmd -ofx -map b.obj a.obj    // change object file order
$ x
core.exception.AssertError at b(4): Assertion failure
----------------
40D01C
40CE93
40204D
402664
40225B
412759
----------------
  <----- Merged foo!1() instantiation into impure version.


a.obj and b.obj have different instantiation of foo!1, but their
manglings are same, "_D1a11__T3fooVi1Z3fooFZi".
Then the calls of foo!1 jump into same code, that is unfortunately shared.

If we can have different manglings depending on whether foo!1 is pure or not,
module a will have a foo!1 mangled as "_D1a11__T3fooVi1Z3fooFNaNbNfZi", and
module b will have a foo!1 mangled as "_D1a11__T3fooVi1Z3fooFNbNfZi".
And the assertion in b:Line4 will always fail independing of the
object file order in command line.

Kenji Hara
November 17, 2011

>________________________________
>From: Don Clugston <dclugston at googlemail.com>
>
>
>No, I'm worried about noisy breaking of pure/nothrow. It can even go in the other direction. Delete a read from a static variable in the body of a template function (not the signature) and now your code won't link, because the function suddenly became pure. The issue is predictability.
>


First, templates do *not* do well as stale objects or dynamically linked ones (this is from experience with C++).? I remember we had this great idea that we would standardize on std::string for a lot of things in a library at work, where things were dynamically linked.? One upgrade to libstdc++, and bizarro errors start occurring.? We eventually used stlport where we could control the string implementation to avoid surprises.


Second, you *want* the linking to fail if the object is stale.? What if purity or nothrow is *removed* by a change to a function?

For example, you have in your library:

char foo(uint n)(in char[] s) // implicitly pure

{
?? return s[n];

}

void bar()
{
?? foo!3("hello");

}

Now, in a separate program, that is dynamically linked with your lib, you have:

pure int baz()
{
?? return foo!3("gobble") + 5;

}

OK.? So now, you change your library's foo to this:

char foo(uint n)(in char[] s)
{
?? return cast(char)(s[n] + rand()); // oops, rand makes it no-longer pure.

}

Since bar instantiates foo!3, it gets stored in the lib.? Updating the lib but not recompiling the app results in code that runs, but is likely wrong.? I'd rather have it fail to dynamically load because of a missing symbol.

Bottom line, I don't think changing the signature of a function, whether implied or not, and not recompiling dependent code is a valid use case, or at least one we should care about.

-Steve

November 18, 2011
On 18 November 2011 04:48, Steve Schveighoffer <schveiguy at yahoo.com> wrote:
>
>
>>________________________________
>>From: Don Clugston <dclugston at googlemail.com>
>>
>>
>>No, I'm worried about noisy breaking of pure/nothrow. It can even go in the other direction. Delete a read from a static variable in the body of a template function (not the signature) and now your code won't link, because the function suddenly became pure. The issue is predictability.
>>
>
>
> First, templates do *not* do well as stale objects or dynamically linked ones (this is from experience with C++).? I remember we had this great idea that we would standardize on std::string for a lot of things in a library at work, where things were dynamically linked.? One upgrade to libstdc++, and bizarro errors start occurring.? We eventually used stlport where we could control the string implementation to avoid surprises.

It affects more than templates.

> Second, you *want* the linking to fail if the object is stale.? What if purity or nothrow is *removed* by a change to a function?

That direction is fine. The idea behind the current implementation is, that if you don't have the source code to the function, then you _cannot_ rely on implicit purity. You only have purity if it's explicitly written in the source code.

Does the current implementation actually work? Kenji's example is a pretty strong argument that it doesn't. But that's the idea behind it.

> Bottom line, I don't think changing the signature of a function, whether implied or not, and not recompiling dependent code is a valid use case, or at least one we should care about.

The thing is, it includes code which wasn't dependent prior to the introduction of implied purity. For example, function pointers with implicit type deduction. External code doesn't need to be able to see the initializer, it only needs to know the type. Currently, automatically generated di files always include the initializers, and don't put in the deduced type. There'd be a huge speed increase if the initializers were dropped. But we're introducing cases where function bodies must be included, solely for type deduction.

This statement from Kenji is quite plausible:
> But, conservative mangling of template function never rescue anything, IMO. It just decrease the type information and cause inconsistent confusion.

I fear that this is right.