March 12, 2012
Le 12/03/2012 13:51, Alex Rønne Petersen a écrit :
> On 12-03-2012 10:40, Walter Bright wrote:
>> On 3/12/2012 1:08 AM, Martin Nowak wrote:
>>> What's wrong with auto-inference. Inferred attributes are only
>>> strengthening
>>> guarantees.
>>
>> Auto-inference is currently done for lambdas and template functions -
>> why? - because the function's implementation is guaranteed to be visible
>> to the compiler. For other functions, not so, and so the attributes must
>> be part of the function signature.
>
> Isn't auto-inference for templates a Bad Thing (TM) since it may give
> API guarantees that you can end up silently breaking?
>

As long as you can explicitly specify that too, and that you get a compile time error when you fail to provide what is explicitly stated, this isn't a problem.
March 12, 2012
On Sun, 11 Mar 2012 19:54:09 -0400, Walter Bright <newshound2@digitalmars.com> wrote:

> Consider the toHash() function for struct key types:
>
> http://dlang.org/hash-map.html
>
> And of course the others:
>
> const hash_t toHash();
> const bool opEquals(ref const KeyType s);
> const int opCmp(ref const KeyType s);
>
> They need to be, as well as const, pure nothrow @safe.
>
> The problem is:
> 1. a lot of code must be retrofitted
> 2. it's just plain annoying to annotate them
>
> It's the same problem as for Object.toHash(). That was addressed by making those attributes inheritable, but that won't work for struct ones.
>
> So I propose instead a bit of a hack. toHash, opEquals, and opCmp as struct members be automatically annotated with pure, nothrow, and @safe (if not already marked as @trusted).

What about a new attribute @type (or better name?) that means "this function is part of the TypeInfo interface, and has an equivalent xFuncname in TypeInfo_Struct".  Then it implicitly inherits all the attributes of that xFuncname (not necessarily defined by the compiler).

Then, we can have several benefits:

1. This triggers the compiler to complain if we don't correctly define the function (as specified in TypeInfo_Struct).  In other words, it allows the developer to specify "I want this function to go into TypeInfo".
2. It potentially allows additional interface hooks without compiler modification.  For example, you could add xfoo in TypeInfo_Struct, and then every struct you define @type foo() would get a hook there.
3. As you wanted, it eliminates having to duplicate all the attributes.

The one large drawback is, you need to annotate all existing functions.  We could potentially assume that @type is specified on the functions that currently enjoy automatic inclusion in the TypeInfo_Struct instance.  I'd recommend at some point eliminating this hack though.

-Steve
March 12, 2012
On 12-03-2012 14:16, deadalnix wrote:
> Le 12/03/2012 13:51, Alex Rønne Petersen a écrit :
>> On 12-03-2012 10:40, Walter Bright wrote:
>>> On 3/12/2012 1:08 AM, Martin Nowak wrote:
>>>> What's wrong with auto-inference. Inferred attributes are only
>>>> strengthening
>>>> guarantees.
>>>
>>> Auto-inference is currently done for lambdas and template functions -
>>> why? - because the function's implementation is guaranteed to be visible
>>> to the compiler. For other functions, not so, and so the attributes must
>>> be part of the function signature.
>>
>> Isn't auto-inference for templates a Bad Thing (TM) since it may give
>> API guarantees that you can end up silently breaking?
>>
>
> As long as you can explicitly specify that too, and that you get a
> compile time error when you fail to provide what is explicitly stated,
> this isn't a problem.

But people might be relying on your API that just so happens to be pure, but then suddenly isn't!

-- 
- Alex
March 12, 2012
On Mon, 12 Mar 2012 10:40:16 +0100, Walter Bright <newshound2@digitalmars.com> wrote:

> On 3/12/2012 1:08 AM, Martin Nowak wrote:
>> What's wrong with auto-inference. Inferred attributes are only strengthening
>> guarantees.
>
> Auto-inference is currently done for lambdas and template functions - why? - because the function's implementation is guaranteed to be visible to the compiler. For other functions, not so, and so the attributes must be part of the function signature.

A "@safe pure nothrow const" might be used as "@system".
That means someone using a declaration may have a different view
than someone providing the implementation.

Those interface boundaries are also a good place for by-hand annotations
to provide explicit API guarantees and enforce a correct implementation.

Though another issue with inference is that it would require a
depth-first-order for the semantic passes.

I also hope we still don't mangle inferred attributes.
March 12, 2012
Walter:

> toHash, opEquals, and opCmp as struct members be automatically annotated with pure, nothrow, and @safe (if not already marked as @trusted).

I have read the other answers of this thread, and I don't like some of them.

In this case I think this programmer convenience doesn't justify adding one more special case to D purity. So for me it's a -1.

Bye,
bearophile
March 12, 2012
On Monday, March 12, 2012 14:23:28 Alex Rønne Petersen wrote:
> On 12-03-2012 14:16, deadalnix wrote:
> > Le 12/03/2012 13:51, Alex Rønne Petersen a écrit :
> >> On 12-03-2012 10:40, Walter Bright wrote:
> >>> On 3/12/2012 1:08 AM, Martin Nowak wrote:
> >>>> What's wrong with auto-inference. Inferred attributes are only
> >>>> strengthening
> >>>> guarantees.
> >>> 
> >>> Auto-inference is currently done for lambdas and template functions - why? - because the function's implementation is guaranteed to be visible to the compiler. For other functions, not so, and so the attributes must be part of the function signature.
> >> 
> >> Isn't auto-inference for templates a Bad Thing (TM) since it may give API guarantees that you can end up silently breaking?
> > 
> > As long as you can explicitly specify that too, and that you get a compile time error when you fail to provide what is explicitly stated, this isn't a problem.
> 
> But people might be relying on your API that just so happens to be pure, but then suddenly isn't!

True, but without out, pure, @safe, and nothrow are essentially useless with templates, because far too many templates depend on their arguments for whether they can be pure, @safe, and/or nothrow or not. It's attribute inference for templates that made it possible to use something stuff like std.range and std.algorithm in pure functions. Without that, it couldn't be done (at least not without some nasty casting). Attribute inference is necessary for templates.

Now, that _does_ introduce the possibility of a template being to be pure and then not being able to be pure thanks to a change that's made to it or something that it uses, and that makes impossible for any code using it to be pure. CTFE has the same problem. It's fairly easy to have a function which is CTFEable cease to be CTFEable thanks to a change to it, and no one notices. We've had issues with this in the past.

In both cases, I believe that the best solution that we have is to unit test stuff to show that it _can_ be pure, @safe, nothrow, and/or CTFEable if the arguments support it, and then those tests can guarantee that it stays that way in spite of any code changes, since they'll fail if the changes break that.

- Jonathan M Davis
March 12, 2012
On Monday, March 12, 2012 09:14:17 Martin Nowak wrote:
> > So I propose instead a bit of a hack. toHash, opEquals, and opCmp as struct members be automatically annotated with pure, nothrow, and @safe (if not already marked as @trusted).
> 
> How about complete inference instead of a hack?

Because that requires having all of the source code. The fact that we have .di files prevents that. You'd have to be able to guarantee that you can always see the whole source (including the source of anything that the functions call) in order for attribute inferrence to work. The only reason that we can do it with templates is because we _do_ always have their source, and the fact that non- templated functions must have the attributes in their signatures makes it so that the templated functions don't need their source in order to determine their own attributes.

The fact that we can't guarantee that all of the source is available when compiling a particular module seriously hampers any attempts at general attribute inference.

- Jonathan M Davis
March 12, 2012
On 12-03-2012 18:38, Jonathan M Davis wrote:
> On Monday, March 12, 2012 14:23:28 Alex Rønne Petersen wrote:
>> On 12-03-2012 14:16, deadalnix wrote:
>>> Le 12/03/2012 13:51, Alex Rønne Petersen a écrit :
>>>> On 12-03-2012 10:40, Walter Bright wrote:
>>>>> On 3/12/2012 1:08 AM, Martin Nowak wrote:
>>>>>> What's wrong with auto-inference. Inferred attributes are only
>>>>>> strengthening
>>>>>> guarantees.
>>>>>
>>>>> Auto-inference is currently done for lambdas and template functions -
>>>>> why? - because the function's implementation is guaranteed to be visible
>>>>> to the compiler. For other functions, not so, and so the attributes must
>>>>> be part of the function signature.
>>>>
>>>> Isn't auto-inference for templates a Bad Thing (TM) since it may give
>>>> API guarantees that you can end up silently breaking?
>>>
>>> As long as you can explicitly specify that too, and that you get a
>>> compile time error when you fail to provide what is explicitly stated,
>>> this isn't a problem.
>>
>> But people might be relying on your API that just so happens to be pure,
>> but then suddenly isn't!
>
> True, but without out, pure, @safe, and nothrow are essentially useless with
> templates, because far too many templates depend on their arguments for
> whether they can be pure, @safe, and/or nothrow or not. It's attribute
> inference for templates that made it possible to use something stuff like
> std.range and std.algorithm in pure functions. Without that, it couldn't be
> done (at least not without some nasty casting). Attribute inference is
> necessary for templates.
>
> Now, that _does_ introduce the possibility of a template being to be pure and
> then not being able to be pure thanks to a change that's made to it or
> something that it uses, and that makes impossible for any code using it to be
> pure. CTFE has the same problem. It's fairly easy to have a function which is
> CTFEable cease to be CTFEable thanks to a change to it, and no one notices.
> We've had issues with this in the past.

That could be solved with a @ctfe attribute or something, no? Like, if the function has @ctfe, go through all possible CTFE paths (excluding !__ctfe paths of course) and make sure they are CTFEable.

>
> In both cases, I believe that the best solution that we have is to unit test
> stuff to show that it _can_ be pure, @safe, nothrow, and/or CTFEable if the
> arguments support it, and then those tests can guarantee that it stays that
> way in spite of any code changes, since they'll fail if the changes break
> that.
>
> - Jonathan M Davis


-- 
- Alex
March 12, 2012
On Monday, March 12, 2012 18:44:06 Alex Rønne Petersen wrote:
> > Now, that _does_ introduce the possibility of a template being to be pure and then not being able to be pure thanks to a change that's made to it or something that it uses, and that makes impossible for any code using it to be pure. CTFE has the same problem. It's fairly easy to have a function which is CTFEable cease to be CTFEable thanks to a change to it, and no one notices. We've had issues with this in the past.
> 
> That could be solved with a @ctfe attribute or something, no? Like, if the function has @ctfe, go through all possible CTFE paths (excluding !__ctfe paths of course) and make sure they are CTFEable.

1. That goes completely against how CTFE was designed in that part of the idea was that you _wouldn't_ have to annotate it.

2. I don't really know how feasible that would be. At minimum, the fact that CTFE works with classes now would probably render it completely infeasible for classes, since they're polymorphic, and the compiler can't possibly know all of the possible types that could be passed to the function. Templates would screw it over too for the exact same reasons that they can have issues with pure, @safe, and nothrow. It may or may not be feasible without classes or templates being involved.

So, no, I don't think that @ctfe would really work. And while I agree that the situation isn't exactly ideal, I don't really see a way around it. Unit tests _do_ catch it for you though. The only thing that they can't catch is whether the template is going to be pure, nothrow, @safe, and/or CTFEable with _your_ arguments to it, but as long as it's pure, nothrow, @safe, and/or CTFEable with _a_ set of arguments, it will generally be the fault of the arguments when such a function fails to be pure, nothrow, @safe, and/or CTFEable as expected. If the unit tests don't hit all of the possible static if-else blocks and all of the possible code paths for CTFE, it could still be a problem, but that just means that the unit tests aren't thorough enough, and more thorough unit tests will fix the problem, as tedious as it may be to do that.

- Jonathan M Davis
March 12, 2012
On Mon, Mar 12, 2012 at 01:55:33PM -0400, Jonathan M Davis wrote: [...]
> So, no, I don't think that @ctfe would really work. And while I agree that the situation isn't exactly ideal, I don't really see a way around it. Unit tests _do_ catch it for you though. The only thing that they can't catch is whether the template is going to be pure, nothrow, @safe, and/or CTFEable with _your_ arguments to it, but as long as it's pure, nothrow, @safe, and/or CTFEable with _a_ set of arguments, it will generally be the fault of the arguments when such a function fails to be pure, nothrow, @safe, and/or CTFEable as expected. If the unit tests don't hit all of the possible static if-else blocks and all of the possible code paths for CTFE, it could still be a problem, but that just means that the unit tests aren't thorough enough, and more thorough unit tests will fix the problem, as tedious as it may be to do that.
[...]

Tangential note: writing unit tests may be tedious, but D's inline unittest syntax has alleviated a large part of that tedium. So much so that I find myself writing as much code in unittests as real code. Which is a good thing, because in the past I'd always been too lazy to write any unittests at all.


T

-- 
Ruby is essentially Perl minus Wall.