Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V now has limited operator overloading #204

Closed
medvednikov opened this issue May 12, 2019 · 8 comments
Closed

V now has limited operator overloading #204

medvednikov opened this issue May 12, 2019 · 8 comments

Comments

@medvednikov
Copy link
Member

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’s philosophy of simplicity and predictability. But since scientific and graphical applications are among V’s 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’s only possible to overload +, -, *, / operators.
  • Calling other functions inside operator functions is not allowed.
  • Operator functions can’t modify their arguments.

https://vlang.io/docs#op

@ntrel
Copy link
Contributor

ntrel commented May 12, 2019

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’t 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.

@ntrel
Copy link
Contributor

ntrel commented May 12, 2019

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.

@rgeorgiev583
Copy link

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).

@ntrel
Copy link
Contributor

ntrel commented May 13, 2019

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.

@data-man
Copy link

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

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

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

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

I hope it's temporary. 😄

@PavelVozenilek
Copy link

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

@medvednikov
Copy link
Member Author

medvednikov commented May 14, 2019

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.

@data-man
Copy link

data-man commented Jun 9, 2019

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants