V: V now has limited operator overloading

Created on 12 May 2019  路  8Comments  路  Source: vlang/v

struct Vec {
    x int
    y int
}

fn (a Vec) str() string { 
    return '{$a.x, $a.y}' 
}

fn (a Vec) + (b Vec) Vec {
    return Vec {
        a.x + b.x , 
        a.y + b.y 
    }
}

fn (a Vec) - (b Vec) Vec {
    return Vec {
        a.x - b.x, 
        a.y - b.y
    }
}

fn main() { 
    a := Vec{2, 3}
    b := Vec{4, 5}
    println(a + b) // ==> "{6, 8}" 
    println(a - b) // ==> "{-2, -2}" 
}

Operator overloading goes against V鈥檚 philosophy of simplicity and predictability. But since scientific and graphical applications are among V鈥檚 domains, operator overloading is very important to have in order to improve readability:

a.add(b).add(c.mul(d)) is a lot less readable than a + b + c * d.

To improve safety and maintainability, operator overloading has several limitations:

  • It鈥檚 only possible to overload +, -, *, / operators.
  • Calling other functions inside operator functions is not allowed.
  • Operator functions can鈥檛 modify their arguments.

https://vlang.io/docs#op

Most helpful comment

Operator [] (array index) may be even more useful than basic arithmetic.

All 8 comments

Great! What about % modulus and unary -vec though, should V support fn -(Vec v) Vec?

Calling other functions inside operator functions is not allowed.

This might be too restrictive, it disallows some reasonable cases that call a function for code reuse rather than algorithmic complexity.

Operator functions can鈥檛 modify their arguments.

Good idea.

Also, for #174 we might want to overload other operators like shift and bitwise operations.

For #203 we might want to overload bitarray[i] indexing. This would also be very useful for container types that support indexing in O(log N) time or better.

I assume e.g. bigint + 2 is not supported.

More potential operators:

  • bigint1 == bigint2, writing != could be lowered to !(bigint1 == bigint2).
  • bigint1 < bigint2 could be lowered to use a comparison function compare(BigInt a, BigInt b) int, returning negative, 0 if same, positive.
  • Appending: container << item.

Edit: Vec doesn't need == overloading.

Great news! However, I consider the syntax you've proposed to be somewhat inconsistent with the language philosophy. Namely, I think operator tokens shouldn't be used as the names of functions which define the overloads. There are two main reasons why this is not a good practice:

  • Operators are not supposed to be identifiers, yet they are used as such.
  • It needlessly complicates the grammar (and respectively, the parser) for the language.

I think the Rust approach to operator overloading is so far the sanest one I've seen, so please consider following that approach in V. (See also what the Rust by example book has to say on the subject).

Rust's solution is interesting, thanks. Trait implementations generally are very flexible, but V doesn't have them (ATM).

In #205 I propose implementing all binary operator overloading with a single template. It also supports the bigint + 2 and 2 + bigint cases.

@medvednikov
Is it the final syntax?
What about this:

fn + (a, b Vec) Vec ...

fn + (a Vec, b int) Vec ...

It鈥檚 only possible to overload +, -, *, / operators.
Calling other functions inside operator functions is not allowed.
Operator functions can鈥檛 modify their arguments.

I hope it's temporary. :smile:

Operator [] (array index) may be even more useful than basic arithmetic.

The syntax had to be either fn (a Vec) + (b Vec) Vec or fn (a Vec) plus (b Vec) Vec, and then people would have to remember that plus means +, mul (mult, times?) means * etc.

So I went for an easier option.

I want to be very careful with this feature. That's why for now there will be no unary operators (use a.negative() instead of -a), no other operators, and no mixed type operators.

Please remember that V's goal is to be a simple and readable language that can be learned in half an hour. Sometimes it means more typing. There are lots of complex languages already.

Calling other functions inside operator functions is not allowed.

This code successfully compiled:

struct Vec {
    x int
    y int
}

fn p(v Vec) {
    println(v)
}

fn (a Vec) str() string {
    return '{$a.x, $a.y}'
}

fn (a Vec) + (b Vec) Vec {
    p(a)
    p(b)
    return Vec {
        a.x + b.x,
        a.y + b.y
    }
}

fn (a Vec) - (b Vec) Vec {
    p(a)
    p(b)
    return Vec {
        a.x - b.x,
        a.y - b.y
    }
}

fn main() {
    a := Vec{2, 3}
    b := Vec{4, 5}
    println(a + b)// ==> "{6, 8}"
    println(a - b)// ==> "{-2, -2}"
}

{2, 3}
{4, 5}
{6, 8}
{2, 3}
{4, 5}
{-2, -2}

Please don't restrict calling other functions, it's can be very useful.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jtkirkpatrick picture jtkirkpatrick  路  3Comments

markgraydev picture markgraydev  路  3Comments

radare picture radare  路  3Comments

clpo13 picture clpo13  路  3Comments

oleg-kachan picture oleg-kachan  路  3Comments