Thread overview
Weird UFC and opCall issues
Dec 18, 2014
Jay Pinkman
Dec 18, 2014
Adam D. Ruppe
Dec 18, 2014
Jay Pinkman
Jan 03, 2015
Darrell
Jan 03, 2015
Darrell
Jan 03, 2015
Darrell
Jan 03, 2015
ted
Jan 03, 2015
Ali Çehreli
Jan 03, 2015
Darrell
December 18, 2014
void main () {
    struct X {
        string x;

        void opCall (string y) {
            import std.stdio;
            writeln("%s %s!", x, y);
        }
    }

    auto x = X("hello");
    "world".x;
}

source/main.d(12): Error: need 'this' for 'opCall' of type 'void(string y)'
source/main.d(13): Error: no property 'x' for type 'string'

but why?
December 18, 2014
On Thursday, 18 December 2014 at 02:42:32 UTC, Jay Pinkman wrote:
> source/main.d(12): Error: need 'this' for 'opCall' of type 'void(string y)'

D doesn't have a really clean separation between static and non-static methods. It sees an opCall and thinks you're trying to call it, but since it isn't static, it complains you don't have a this.

> source/main.d(13): Error: no property 'x' for type 'string'

I don't think UFCS works with structs nor local variables anyway, so this error makes sense to me.
December 18, 2014
On Thursday, 18 December 2014 at 02:45:01 UTC, Adam D. Ruppe wrote:
> D doesn't have a really clean separation between static and non-static methods.

hmm.. i thought that's what 'static' is for.

> It sees an opCall and thinks you're trying to call it, but since it isn't static, it complains you don't have a this.

so it's bug i should report or some idiosyncracy?

> I don't think UFCS works with structs nor local variables anyway, so this error makes sense to me.

i guess i should request this. in my other code i use a struct to represent a transformation so it makes perfect sense to use it in UFCS fashion.
January 03, 2015
Fails with:
    t.d(34): Error: need 'this' for 'opCall' of type 'int()'

Also opCall seems to be required to create a range.

class Test
{
  int opCall()
  {
    return 1;
  }

  @property int front()
  {
    return 2;
  }

  void popFront()
  {
  }

  @property bool empty()
  {
    return false;
  }

};

void main(){
  ubyte [] p1;
  Test();
}
January 03, 2015
Ooops.
Test() wasn't valid.
Still working to create a range object that iterates over an internal data struct. But this was may error.


On Saturday, 3 January 2015 at 20:26:41 UTC, Darrell wrote:
> Fails with:
>     t.d(34): Error: need 'this' for 'opCall' of type 'int()'
>
> Also opCall seems to be required to create a range.
>
> class Test
> {
>   int opCall()
>   {
>     return 1;
>   }
>
>   @property int front()
>   {
>     return 2;
>   }
>
>   void popFront()
>   {
>   }
>
>   @property bool empty()
>   {
>     return false;
>   }
>
> };
>
> void main(){
>   ubyte [] p1;
>   Test();
> }

January 03, 2015
Seems when creating your own ranges they can't be a class.
Must be a struct or Segmentation fault (core dumped) will follow.

This works as long as Test is a struct.

struct Test
{
  @property int front()
  {
    return 2;
  }

  void popFront()
  {
  }

  enum bool empty = false;
};

static assert(isInputRange!Test);

void mainx(){
  Test x;
  writeln(x.take(1));
}
January 03, 2015
Darrell wrote:

> Seems when creating your own ranges they can't be a class.
> Must be a struct or Segmentation fault (core dumped) will follow.
> 
> This works as long as Test is a struct.
> 
> struct Test
> {
>    @property int front()
>    {
>      return 2;
>    }
> 
>    void popFront()
>    {
>    }
> 
>    enum bool empty = false;
> };
> 
> static assert(isInputRange!Test);
> 
> void mainx(){
>    Test x;
>    writeln(x.take(1));
> }


With classes, you need to create an instance, so (adjusting some of your previous code) this works:

import std.range;
import std.stdio;

class Test
{
   @property int front()
   {
     return 2;
   }

   void popFront()
   {
   }

   @property bool empty()
   {
     return false;
   }

};
static assert(isInputRange!Test);

void main(){
   ubyte [] p1;
    Test myTest = new Test();
    writeln(myTest.take(1));
}






January 03, 2015
On 01/03/2015 12:26 PM, Darrell wrote:

> Fails with:
>      t.d(34): Error: need 'this' for 'opCall' of type 'int()'
>
> Also opCall seems to be required to create a range.

D has a feature that does not exists e.g. in C++: You can call the type itself as a function. The 'Test()' syntax is a call to that type's static opCall().

>
> class Test
> {
>    int opCall()
>    {
>      return 1;
>    }

Not being static, that would require an instance of the Test class.

>
>    @property int front()
>    {
>      return 2;
>    }

You may want to define that member function 'const' as well.

>
>    void popFront()
>    {
>    }
>
>    @property bool empty()
>    {
>      return false;
>    }

That can be 'const' as well.

>
> };

D does not require that semicolon.

>
> void main(){
>    ubyte [] p1;
>    Test();
> }

I am removing the opCall and assuming that you actually want a ubyte I am returning a ubyte from front().

Also note the almost-mandatory-with-ranges convenience function 'test()' below, which hides the invocation of 'new':

class Test
{
  @property ubyte front()
  {
    return 2;
  }

  void popFront()
  {
  }

  @property bool empty()
  {
    return false;
  }
}

Test test()
{
    return new Test();
}

/* Alternatively, you can move test() inside Test as a static opCall:

    static Test opCall()
    {
        return new Test();
    }

Then, the syntax in main could be

    ubyte [] p1 = Test().take(3).array;

*/

import std.stdio;
import std.range;

void main(){
  ubyte [] p1 = test().take(3).array;
  assert(p1 == [ 2, 2, 2 ]);
}

Ali

January 03, 2015
Thanks for the feedback.

>> With classes, you need to create an instance

Need to read up classes vs struct.

This bit of syntax was very intresting.

/* Alternatively, you can move test() inside Test as a static opCall:

    static Test opCall()
    {
        return new Test();
    }

Then, the syntax in main could be

    ubyte [] p1 = Test().take(3).array;

*/


Very impressed with D and starting a new job. Might be able to use it.