Thread overview
[D1] struct opEquals questions
Mar 18, 2010
qwerty
Mar 18, 2010
bearophile
Mar 18, 2010
qwerty
Mar 18, 2010
bearophile
Mar 18, 2010
qwerty
Mar 18, 2010
bearophile
Mar 18, 2010
qwerty
Mar 18, 2010
bearophile
Mar 18, 2010
qwerty
March 18, 2010
In my unittest I tried to test out my rotate function.
assert(Vec2(1,2).rotate(90) == Vec(-2,1));
But I got these compile errors:
vector.d(156): Error: function vector.Vec.opEquals (Vec) does not match parameter types (void)
vector.d(156): Error: cannot implicitly convert expression (opCall(1,2).rotate(opCall(90))) of type void to Vec*

2 questions:
My opEquals takes an Vec2 and not a *Vec2, is this wrong?
Why is return value of the rotate function compared and not the rotated struct literal?
March 18, 2010
qwerty:
> My opEquals takes an Vec2 and not a *Vec2, is this wrong?

It's OK. D1 docs say:
Structs and unions (hereafter just called structs) can provide a member function:
int opEquals(S s)
or:
int opEquals(S* s)


> Why is return value of the rotate function compared and not the rotated struct literal?

You can add a  return this or return *this at the end of the rotate method.

Bye,
bearophile
March 18, 2010
qwerty wrote:
> In my unittest I tried to test out my rotate function.
> assert(Vec2(1,2).rotate(90) == Vec(-2,1));
> But I got these compile errors:
> vector.d(156): Error: function vector.Vec.opEquals (Vec) does not match parameter types (void)
> vector.d(156): Error: cannot implicitly convert expression (opCall(1,2).rotate(opCall(90))) of type void to Vec*
> 
> 2 questions:
> My opEquals takes an Vec2 and not a *Vec2, is this wrong?
> Why is return value of the rotate function compared and not the rotated struct literal?

2 problems:

1. You call the struct Vec some places and Vec2 others.

2. My guess is that the compiler complains about Vec* because Vec is a struct, not a class, and you have written 'new Vec' somewhere.  Am I right?

If that is the case, remember that for structs, 'new' returns a pointer, whereas for classes it returns a reference.

-Lars
March 18, 2010
Lars T. Kyllingstad Wrote:

> qwerty wrote:
> > In my unittest I tried to test out my rotate function.
> > assert(Vec2(1,2).rotate(90) == Vec(-2,1));
> > But I got these compile errors:
> > vector.d(156): Error: function vector.Vec.opEquals (Vec) does not match parameter types (void)
> > vector.d(156): Error: cannot implicitly convert expression (opCall(1,2).rotate(opCall(90))) of type void to Vec*
> > 
> > 2 questions:
> > My opEquals takes an Vec2 and not a *Vec2, is this wrong?
> > Why is return value of the rotate function compared and not the rotated struct literal?
> 
> 2 problems:
> 
> 1. You call the struct Vec some places and Vec2 others.
That's me trying to make the code more readable :(
All should be Vec2

> 
> 2. My guess is that the compiler complains about Vec* because Vec is a struct, not a class, and you have written 'new Vec' somewhere.  Am I right?
> 
> If that is the case, remember that for structs, 'new' returns a pointer, whereas for classes it returns a reference.
> 
> -Lars

Sorry about my typos, bearophile luckily read right over them :)


March 18, 2010
bearophile Wrote:

> qwerty:
> > My opEquals takes an Vec2 and not a *Vec2, is this wrong?
> 
> It's OK. D1 docs say:
> Structs and unions (hereafter just called structs) can provide a member function:
> int opEquals(S s)
> or:
> int opEquals(S* s)
> 
> 
> > Why is return value of the rotate function compared and not the rotated struct literal?
> 
> You can add a  return this or return *this at the end of the rotate method.
If I return *this, I should also provide the *S version of opEquals? int opEquals(S* s) { return (i1 ==*s.i1 && i2 ==*s.i2); }

What happens with the return value if it isn't used?
Vec2(1,2).rotate(90);
I mean, where will the *this end up? Or will the compiler not return it at all?

> 
> Bye,
> bearophile

March 18, 2010
qwerty:
> If I return *this, I should also provide the *S version of opEquals?

If you don't provide a necessary operator the compiler complaints.


> What happens with the return value if it isn't used?

The function is one and it doesn't change, it has to be the same for everyone that calls it (time ago I have suggested for a compile time flag that's defined inside functions to know if their result is used, to avoid computing it in some situations, turning the single function in a kind of templated function, but I am not sure it can work well if you have function pointers. So you need a single entry point for two functions).


> I mean, where will the *this end up? Or will the compiler not return it at all?

The function returns it, but the result is ignored. In such situations reading a little the asm helps.

Bye,
bearophile
March 18, 2010
bearophile Wrote:

> qwerty:
> > If I return *this, I should also provide the *S version of opEquals?
> 
> If you don't provide a necessary operator the compiler complaints.
> 
> 
> > What happens with the return value if it isn't used?
> 
> The function is one and it doesn't change, it has to be the same for everyone that calls it (time ago I have suggested for a compile time flag that's defined inside functions to know if their result is used, to avoid computing it in some situations, turning the single function in a kind of templated function, but I am not sure it can work well if you have function pointers. So you need a single entry point for two functions).

For a function without any side effects, it shouldn't be a problem.. I think :)

> 
> 
> > I mean, where will the *this end up? Or will the compiler not return it at all?
> 
> The function returns it, but the result is ignored. In such situations reading a little the asm helps.

Yet another thing I should learn.. asm :)

> 
> Bye,
> bearophile

March 18, 2010
qwerty:
> For a function without any side effects, it shouldn't be a problem.. I think :)

Ignoring the return value of a function without side effects (in D2 pure functions or nothrow pure functions) has to be an error. I even have a bug report for this, because it's the same situation as an expression like:
a + 5;
that the compiler sees as an error.

Bye,
bearophile
March 18, 2010
bearophile Wrote:
>> (time ago I have suggested for a compile time flag that's defined inside functions to know if their result is used, to avoid computing it in some situations, turning the single function in a kind of templated function, but I am not sure it can work well if you have function pointers. So you need a single entry point for two functions).
> qwerty:
> > For a function without any side effects, it shouldn't be a problem.. I think :)
> 
> Ignoring the return value of a function without side effects (in D2 pure functions or nothrow pure functions) has to be an error. I even have a bug report for this, because it's the same situation as an expression like:
> a + 5;
> that the compiler sees as an error.
> 
I meant this:

function is with side effects --> normal func()
function is without side effect --> generate 2 version of the function
 *if compiler can see no return is required --> point to noReturnCalc version
  if compiler doesn't know --> point to returnCalc version
  if called through pointer --> point to returnCalc version
As the function has no side effect, it doesn't matter there are two different versions (no static members etc.)

This will only speed up the *
Hope it makes any sense :D
March 18, 2010
Inside free functions there can be a locally defined compile-time boolean constant like __used_return. If you use this constant inside a function the compiler creates two versions of the function that share the same static variables (if the function is a template then each pair of instantiated functions share the same static variables). Inside the function you can use a static if to not compute the return value if __used_return is false (so in this case the function has void return type).

qwerty:
>   if compiler doesn't know --> point to returnCalc version
>   if called through pointer --> point to returnCalc version

Yes, the default has to be __used_return = true. But I don't know if this is safe enough.


So this:


int foo(int x) {
    int val;
    val += x;
    static if (__used_return)
        return val + 1;
}
void main() {
    int y = foo(5);
    foo(6);
    int function(int) tf = &foo;
    alias typeof(foo) TF;
}



Once desugared is like:

int _foo_val;
int foo_ret(int x) {
    _foo_val += x;
    return _foo_val + 1;
}
void foo_void(int x) {
    _foo_val += x;
}
void main() {
    int y = foo_ret(5);
    foo_void(6);
    int function(int) tf = &foo_ret;
    alias typeof(foo_ret) TF;
}


In practice I don't think this can be useful enough.

Bye,
bearophile