Zardoz89
Zardoz89

Reputation: 621

Language D ; structs, immutable data and weird error

I'm learning language D. My first try is a simple 2d Vector that I can add, substract, dot product, etc... I have this error when I try to compile:

Error :

Error: (Vector2d __ctmp1245 = D4math2v28Vector2d6_initZ; , __ctmp1245).this(this._x / l,this._y / l) is not mutable

Note : The error is related to Vector2d.dir()

The code is :

import std.math;
public struct Vector2d {

private const real _x;
private const real _y;

this(in real x, in real y) {
    _x = x; _y = y;
}

// Basic Properties ***************************************

@property const real X () { return _x; }

@property const real Y () { return _y; }

@property const real length () { return sqrt(_x*_x + _y*_y); }

// Operations ***************************************   

/**
* Define Equality 
*/
const bool opEquals(ref const Vector2d rhs) {
    return  approxEqual(_x, rhs._x) &&  approxEqual(_y, rhs._y);
}

/**
* Define unary operators + and - (+v)
*/
ref Vector2d opUnary(string op)() const
    if (op == "+" || op == "-")
{
    return Vector2d(mixin(op~"_x"), mixin(op~"_y"));
}

/**
* Define binary operator + and - (v1 + v2)
*/
ref Vector2d opBinary(string op) (ref const Vector2d rhs)
    if (op == "+" || op == "-")
{
    return Vector2d(mixin("_x" ~ op ~ "rhs._x"),mixin("_y" ~ op ~ "rhs._y"));
}

/**
* Scalar multiplication & division (v * 7)
*/
ref Vector2d opBinary(string op) (ref const real rhs) const
    if (op == "*" || op == "/")
{
    return Vector2d(mixin("_x" ~ op ~ "rhs"),mixin("_y" ~ op ~ "rhs"));
}

/**
* Dot Product (v1 * v2)
*/
ref real opBinary(string op) (ref const Vector2d rhs) const
    if (op == "*") {
        return _x*rhs._x + _y*rhs._y;
} 

/**
* Obtain the director vector of this vector.
*/
ref Vector2d dir() const {
    auto l = this.length();
    return Vector2d(_x / l, _y /l);
}

/**
* Obtains the projection of this vector over other vector
* Params:
*   b = Vector over project this vector
*/
ref Vector2d projectOnTo(in Vector2d b) const {
    return  b.dir() * (this * b.dir());
}

    }

I don't understand why I have this error. Plus I try to change Type Qualifiers unsuccessful. Even I get the same error if i try this :

    ref Vector2d dir() const {
    auto l = this.length();
    return Vector2d(2,3);
 }

EDIT :

I tried removing "const" from attributes and removing "ref" from Dot product (I get a advice that not was lvalue) . The error is now this :

src/math/v2.d(82): Error: this.opBinary(b.dir()) is not an lvalue

The line 82 is :

return  b.dir() * (this * b.dir());

AutoANSWER:

I fixed the last error, I changed ProjectOnTo to this :

ref Vector2d projectOnTo(in Vector2d b) const {
    auto a = this * b.dir();
    return  b.dir() * a;
}

Plus I run a unit test and looks that Vector2d It's doing ok.

So, finally I know now that I can't use immutable variables for a struct attributes, but I dont understand why.

Upvotes: 1

Views: 372

Answers (2)

ratchet freak
ratchet freak

Reputation: 48216

drop off the const qualifiers of the fields

public struct Vector2d {

    private real _x;
    private real _y;

    this(in real x, in real y) {
        _x = x; _y = y;
    }
    //...

the const is unnecessary and it will block you from simple assignment:

Vector2d v;
v = Vector2d(0,0);

this wont wont compile

and do remember that generic functions (the opBinary and opUnary) are only tested on syntax when they are parsed not on correctness of the code (your opUnary returns a Vector!T but the T generic type is never declared (and thus undefined) yet this passes compilation...)


edit I've made my own struct with operator overloads and except for opCmp and opEquals I don't use ref const for parameters just const (in works just as well for this)

edit2 I've found it easiest to understand structs as groups of variables that can be declared, assigned and used at the same time with a few extra functions defined around the group of vars

so Vector2D v; in your original code would then be translated as const real v__x; const real v__y; the assignment v = Vector(0,0); would then be (after inlining the constructor) translated as v__x = 0;v__y = 0;

but as v__x is declared as const this wont be allowed

Upvotes: 2

vines
vines

Reputation: 5225

I've tried to rewrite the body of dir() as

Vector2d v = Vector2d(0, 0);
return v;

and saw a nice error message then:

vector2D.d(67): Error: variable vector2D.Vector2d.dir.v cannot modify struct with immutable members
vector2D.d(67): Error: escaping reference to local variable v

I don't understand how a variable could modify a struct, but this gave me the hint: why did you define _x and _y as const? I've removed the const from their declarations, and it has compiled :)

Upvotes: 0

Related Questions