May 29, 2019
On Wed, May 29, 2019 at 6:55 AM Mike Franklin via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On Tuesday, 28 May 2019 at 16:08:38 UTC, Andrei Alexandrescu wrote:
> > int fun(int) pure;
> > int fun(int);
> >
> > pure int gun(int x)
> > {
> >    return fun(x);
> > }
>
> I think it really depends on the attribute.  I haven't thought too much about the other attributes, but for `pure` I don't see the use case.  If you can make the implementation of `fun(int)` pure, why would you need an additional impure implementation?

Right. nothrow is the only one that makes any sense at all to me, I've thought that overloading on nothrow might be useful once or twice. Otherwise... pure; like you say, @nogc; signature is always different anyway, @safe; makes no sense...
May 30, 2019
On Thursday, 30 May 2019 at 05:24:21 UTC, Manu wrote:
> Right. nothrow is the only one that makes any sense at all to me, I've thought that overloading on nothrow might be useful once or twice. Otherwise... pure; like you say, @nogc;

I wonder if overloading on nothrow could be better done as overloading on return value. Either you get "return value or exception" or you get "wrapped return value".

What other use case is there?

May 30, 2019
On Wednesday, 29 May 2019 at 13:53:37 UTC, Mike Franklin wrote:
> On Tuesday, 28 May 2019 at 16:08:38 UTC, Andrei Alexandrescu wrote:
>> int fun(int) pure;
>> int fun(int);
>>
>> pure int gun(int x)
>> {
>>    return fun(x);
>> }
>
> I think it really depends on the attribute.  I haven't thought too much about the other attributes, but for `pure` I don't see the use case.  If you can make the implementation of `fun(int)` pure, why would you need an additional impure implementation?

A use case I found is that the pure overload can use GC to allocate memory for CTFE, while the impure overload can use a custom allocator for run time. The compiler always chose pure overload, so I gave up on purity altogether.
May 30, 2019
On Thursday, 30 May 2019 at 05:24:21 UTC, Manu wrote:
> On Wed, May 29, 2019 at 6:55 AM Mike Franklin via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>>
>> On Tuesday, 28 May 2019 at 16:08:38 UTC, Andrei Alexandrescu wrote:
>> > int fun(int) pure;
>> > int fun(int);
>> >
>> > pure int gun(int x)
>> > {
>> >    return fun(x);
>> > }
>>
>> I think it really depends on the attribute.  I haven't thought too much about the other attributes, but for `pure` I don't see the use case.  If you can make the implementation of `fun(int)` pure, why would you need an additional impure implementation?
>
> Right. nothrow is the only one that makes any sense at all to me, I've thought that overloading on nothrow might be useful once or twice. Otherwise... pure; like you say, @nogc; signature is always different anyway, @safe; makes no sense...

I don't think it is that useful. Consider if you did do the following:

    void foo() nothrow;
    void foo();

    void bar() nothrow
    {
         foo(); // ok useful calls foo() nothrow
    }

    void ree()
    {
        foo(); // ambiguous can call both, should be an error
    }


It can call either function if the callee isn't nothrow. I don't think it should implicitly call the function without the nothrow either. It really varies on the situation which one should be called, you may want the variant that doesn't throw an exception. It would be surprising if you have a function defined as nothrow, then add an overload without the nothrow and now it is now calling a different overload in functions without nothrow. At which point this isn't all that useful, it will work as expected in nothrow functions but then you will have to explicitly choose which one to use otherwise. Which is basically the situation now with nothrow, you just have to use a different function name.


May 30, 2019
On Thursday, 30 May 2019 at 13:58:20 UTC, Exil wrote:
> I don't think it is that useful. Consider if you did do the following:
>
>     void foo() nothrow;
>     void foo();
>
>     void bar() nothrow
>     {
>          foo(); // ok useful calls foo() nothrow
>     }
>
>     void ree()
>     {
>         foo(); // ambiguous can call both, should be an error
>     }
>
>
> It can call either function if the callee isn't nothrow. I don't think it should implicitly call the function without the nothrow either. It really varies on the situation which one should be called, you may want the variant that doesn't throw an exception. It would be surprising if you have a function defined as nothrow, then add an overload without the nothrow and now it is now calling a different overload in functions without nothrow. At which point this isn't all that useful, it will work as expected in nothrow functions but then you will have to explicitly choose which one to use otherwise. Which is basically the situation now with nothrow, you just have to use a different function name.

I think is is orthogonal to how `const` is used on non-static member functions:

struct Example
{
    void member() const { }
    void member() /*mutable*/ { }
}

Example ex;
ex.member(); // calls mutable

It could call either function if the callee is mutable. People all over the board think it should implicitly call the function without the const. It could vary on the situation which one should be called, but mostly, you may want the variant that uses mutability to its advantage. Nobody finds it surprising if you have a const method, then add a mutable overload and now it is now calling a different overload in functions where the object is mutable.

You could handle mutable and const methods the same: Tell people they need different names. It just doesn't look so nice with operators (fixed names, you cannot choose another), type inference and meta-programming.

Nobody sees a problem with that, and it's about the same thing: The context of the call decides which overload is chosen. It is nothing new, C++ does it since the beginning.

As I see it, this is can be made into an argument for a `nothrow(some_ct_bool_value)` attribute.
May 31, 2019
On Thu, May 30, 2019 at 12:55 AM Ola Fosheim Grøstad via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On Thursday, 30 May 2019 at 05:24:21 UTC, Manu wrote:
> > Right. nothrow is the only one that makes any sense at all to me, I've thought that overloading on nothrow might be useful once or twice. Otherwise... pure; like you say, @nogc;
>
> I wonder if overloading on nothrow could be better done as overloading on return value. Either you get "return value or exception" or you get "wrapped return value".
>
> What other use case is there?

out params. wrapping return values kinda sucks, inhibits RVO. overloading on return value seems problematic... how would that work?

May 31, 2019
On Friday, 31 May 2019 at 17:52:28 UTC, Manu wrote:
> out params. wrapping return values kinda sucks, inhibits RVO.

It can, yes. It requires more advanced RVO optimizations to avoid it.

> overloading on return value seems problematic... how would that work?

The compiler narrows down possible return types until one is left. The simple version would require an explicit type, a more advanced version would look at how the result is used and use that to narrow down the candidate types until one is left.




May 31, 2019
On Fri, May 31, 2019 at 11:35 AM Ola Fosheim Grøstad via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On Friday, 31 May 2019 at 17:52:28 UTC, Manu wrote:
> > out params. wrapping return values kinda sucks, inhibits RVO.
>
> It can, yes. It requires more advanced RVO optimizations to avoid it.
>
> > overloading on return value seems problematic... how would that work?
>
> The compiler narrows down possible return types until one is left. The simple version would require an explicit type, a more advanced version would look at how the result is used and use that to narrow down the candidate types until one is left.

A fun() { return A(); }
B fun() { return B(); }

fun(); // <- return value ignored

...?

May 31, 2019
On Friday, 31 May 2019 at 21:39:10 UTC, Manu wrote:
> On Fri, May 31, 2019 at 11:35 AM Ola Fosheim Grøstad via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>>
>> On Friday, 31 May 2019 at 17:52:28 UTC, Manu wrote:
>> > out params. wrapping return values kinda sucks, inhibits RVO.
>>
>> It can, yes. It requires more advanced RVO optimizations to avoid it.
>>
>> > overloading on return value seems problematic... how would that work?
>>
>> The compiler narrows down possible return types until one is left. The simple version would require an explicit type, a more advanced version would look at how the result is used and use that to narrow down the candidate types until one is left.
>
> A fun() { return A(); }
> B fun() { return B(); }
>
> fun(); // <- return value ignored
>
> ...?

Ambiguous. cast(A)fun(); to call that specific overload. I guess that means cast(void)cast(A)fun(); if fun is pure...

--
  Simen

June 01, 2019
On Thursday, 30 May 2019 at 15:30:26 UTC, Q. Schroll wrote:
> On Thursday, 30 May 2019 at 13:58:20 UTC, Exil wrote:
>> I don't think it is that useful. Consider if you did do the following:
>>
>>     void foo() nothrow;
>>     void foo();
>>
>>     void bar() nothrow
>>     {
>>          foo(); // ok useful calls foo() nothrow
>>     }
>>
>>     void ree()
>>     {
>>         foo(); // ambiguous can call both, should be an error
>>     }
>>
>>
>> It can call either function if the callee isn't nothrow. I don't think it should implicitly call the function without the nothrow either. It really varies on the situation which one should be called, you may want the variant that doesn't throw an exception. It would be surprising if you have a function defined as nothrow, then add an overload without the nothrow and now it is now calling a different overload in functions without nothrow. At which point this isn't all that useful, it will work as expected in nothrow functions but then you will have to explicitly choose which one to use otherwise. Which is basically the situation now with nothrow, you just have to use a different function name.
>
> I think is is orthogonal to how `const` is used on non-static member functions:
>
> struct Example
> {
>     void member() const { }
>     void member() /*mutable*/ { }
> }
>
> Example ex;
> ex.member(); // calls mutable
>
> It could call either function if the callee is mutable. People all over the board think it should implicitly call the function without the const. It could vary on the situation which one should be called, but mostly, you may want the variant that uses mutability to its advantage. Nobody finds it surprising if you have a const method, then add a mutable overload and now it is now calling a different overload in functions where the object is mutable.
>
> You could handle mutable and const methods the same: Tell people they need different names. It just doesn't look so nice with operators (fixed names, you cannot choose another), type inference and meta-programming.
>
> Nobody sees a problem with that, and it's about the same thing: The context of the call decides which overload is chosen. It is nothing new, C++ does it since the beginning.
>
> As I see it, this is can be made into an argument for a `nothrow(some_ct_bool_value)` attribute.

It is not orthogonal at all. If you want to look at it this way. It looks like it is othrogonal to nothrow because of the syntactic sugar. What the actual definition is this:


    void member( ref const(Example) _this );
    void member( ref Example _this );

It is part of the parameters, which is perfectly legal even as a static function not part of an object. Yes you can call either, but one is an exact type match and is chosen instead.

Looking at nothrow now, it doesn't have any parameters that can be used to evaluate the function.

    void foo() nothrow;
    void foo();

In the case of const for an object, it is just syntactic sugar for an already existing feature that follows the rules for function selection. This proposed changed will be adding another layer to that, and it will be quite messy due to how templates auto infer their attributes.

If you want to draw parallels with C++, you can't define a function as nothrow and non-nothrow in C++ (noexcept). It has to be defined as either one or the other.