Thread overview
function vs. delegate in a unittest
Apr 21, 2019
Manfred Nowak
Apr 21, 2019
rikki cattermole
Apr 21, 2019
Manfred Nowak
Apr 21, 2019
Meta
Apr 21, 2019
Manfred Nowak
Apr 21, 2019
Bastiaan Veelo
Apr 21, 2019
ag0aep6g
April 21, 2019
Because unittests are special functions, the functions declared within the body of a unittest have the type of a `delegate'. By this the intent to include a unittest for functions with the type of a `function' requires the definition of a function outside of the body of the unittest.

1: In the docs for unittesting https://dlang.org/spec/unittest.html this is a case of usage of `version( unittest)' in currently number "7.".

2: Has someone proven, that a super type for `function' and `delegate' is not existent or too difficult to implement in the compiler? Or is there a good reason for requiring coders to manage different versions for both types of functions?
April 21, 2019
On 21/04/2019 6:35 PM, Manfred Nowak wrote:
> Because unittests are special functions, the functions declared within the body of a unittest have the type of a `delegate'. By this the intent to include a unittest for functions with the type of a `function' requires the definition of a function outside of the body of the unittest.

---
void main()
{
    void func() {
    }

    pragma(msg, typeof(&func));
}

unittest {
    void func() {
    }

    pragma(msg, typeof(&func));
}
---

void delegate() pure nothrow @nogc @safe
void delegate() pure nothrow @nogc @safe

vs

---
void main()
{
    static void func() {
    }

    pragma(msg, typeof(&func));
}

unittest {
    static void func() {
    }

    pragma(msg, typeof(&func));
}
---

void function() pure nothrow @nogc @safe
void function() pure nothrow @nogc @safe
April 21, 2019
On Sunday, 21 April 2019 at 06:39:37 UTC, rikki cattermole wrote:
>     static void func() {

thy for the hint, that one can use `static' to virtually lift the definition of a function up to the local root of the hierarchy, which makes my oversimplified argument invalid for unittests.

But this seems not to solve the underlying problem:

unittest{
         void f (){}
  static void fs(){}
  struct S( T){
    T* f;
    this( T)( T fl){
      f= fl;
    }
  }
//auto sf = new S !( typeof( f ))( &f );
  auto sfs= new S !( typeof( fs))( &fs);
}

Under dmd 2.085.1 this code compiles.
But replacing the comment slashes by white space gives an error:
  cannot implicitly convert expression
    [...] delegate [...] to function [...]

So that's not a problem of unittests but of templates?
April 21, 2019
On Sunday, 21 April 2019 at 08:52:40 UTC, Manfred Nowak wrote:
> Under dmd 2.085.1 this code compiles.
> But replacing the comment slashes by white space gives an error:
>   cannot implicitly convert expression
>     [...] delegate [...] to function [...]

Are you certain about that? Trying it with the "All dmd compilers" option on run.dlang.io seems to suggest that it won't compile with any version of dmd:
https://run.dlang.io/is/MdEpux

As per the language rules, your example can't work, because not marking `f` as static means that it will keep a context pointer to the unittest stack frame (unittests are really just functions that get automatically run).

Unless you mark it static, or there is some functionality implemented in the future where the compiler can statically determine that f doesn't access anything through its context pointer, and can therefore be converted to a `function` as opposed to a `delegate`, this won't work.
April 21, 2019
On Sunday, 21 April 2019 at 16:49:54 UTC, Meta wrote:
[...]
> can therefore be converted to a `function`
[...]

thy. I know realize, that the error message tempted me onto the wrong track.

The error message excluded "implicit" conversions only, but explicit conversions are excluded too by deprecation, which means, that conversions between `delegate' and `function' are currently forbidden in both directions.

This reopens number "2." in the original posting.


April 21, 2019
On Sunday, 21 April 2019 at 08:52:40 UTC, Manfred Nowak wrote:
> On Sunday, 21 April 2019 at 06:39:37 UTC, rikki cattermole wrote:
>>     static void func() {
>
> thy for the hint, that one can use `static' to virtually lift the definition of a function up to the local root of the hierarchy, which makes my oversimplified argument invalid for unittests.
>
> But this seems not to solve the underlying problem:
>
> unittest{
>          void f (){}
>   static void fs(){}
>   struct S( T){
>     T* f;
>     this( T)( T fl){
>       f= fl;
>     }
>   }
> //auto sf = new S !( typeof( f ))( &f );
>   auto sfs= new S !( typeof( fs))( &fs);
> }
>
> Under dmd 2.085.1 this code compiles.
> But replacing the comment slashes by white space gives an error:
>   cannot implicitly convert expression
>     [...] delegate [...] to function [...]
>
> So that's not a problem of unittests but of templates?

This works:

unittest
{
         void f (){}
  static void fs(){}
  struct S( T){
    T f;
    this( T)( T fl){
      f= fl;
    }
  }
  auto sf = new S !( typeof( &f ))( &f );
  auto sfs= new S !( typeof( &fs))( &fs);
}

https://run.dlang.io/is/yu67oN

And regarding "requiring coders to manage different versions for both types of functions": there is std.functional.toDelegate, so if you just support delegates, that is enough -- unless you care about @safe.

Bastiaan.
April 21, 2019
On 21.04.19 08:35, Manfred Nowak wrote:
> 2: Has someone proven, that a super type for `function' and `delegate' is not existent or too difficult to implement in the compiler? Or is there a good reason for requiring coders to manage different versions for both types of functions?

Here's an older thread on how I think functions and delegates could be consolidated pretty easily:

https://forum.dlang.org/post/ofc0lj$2u4h$1@digitalmars.com

As far as I'm aware, there is nothing fundamentally blocking the feature. But pushing the idea further is in no way a priority for me at the moment.

To make it happen, someone would need to implement it in the compiler and convince Walter and Andrei of the change, probably via a DIP.