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

Broken operator overloading for aliased arrays #23213

Open
gechandesu opened this issue Dec 19, 2024 · 3 comments
Open

Broken operator overloading for aliased arrays #23213

gechandesu opened this issue Dec 19, 2024 · 3 comments
Labels
Bug This tag is applied to issues which reports bugs.

Comments

@gechandesu
Copy link
Contributor

gechandesu commented Dec 19, 2024

Describe the bug

Only != and == operators allowed for arrays. But V allows operator overloading. I create an alias for a fixed array and overload <.

The documentation says that this should be enough to generate the >, <=, >=. It seems like that's how it should work.

For now V treats such an alias as an array (which is correct) and forbids me from using <=, >=, >, < directly. But overloading works if type alias is used in struct (as expected lol). See example below.

My usecase: the array of 4 bytes is an IPv4 address, which can also be represented by u32. Therefore, it is logical for it to have the ability to compare even if the address is represented by an array.

Reproduction Steps

Run: https://play.vlang.io/p/b0138dd025

import encoding.binary

type Addr = [4]u8

fn (a Addr) u32() u32 {
	return binary.big_endian_u32_fixed(a)
}

fn (a Addr) < (b Addr) bool {
	dump('overloaded Addr < op call')
	return a.u32() < b.u32()
}

struct Net {
	addr Addr
	mask int
}

fn (n Net) < (other Net) bool {
	dump('overloaded Net < op call')
	if n.addr != other.addr {
		return n.addr < other.addr // it works here
	}
	if n.mask != other.mask {
		return n.mask < other.mask
	}
	return false
}

fn (n Net) == (other Net) bool {
	dump('overloaded Net == op call')
	return n.addr == other.addr && n.mask == other.mask
}

fn main() {
	a := Addr([u8(1), 2, 3, 4]!)
	b := Addr([u8(5), 4, 3, 2]!)
	
	assert a != b
	// assert a > b // but doesn't works here
	
	net_a := Net{a, 24}
	net_b := Net{b, 24}

	assert net_a < net_b  // succesfully calls `Addr < Addr` inside!
	assert net_a != net_b
}

Output:

[op_overload.vv:20] 'overloaded Net < op call': overloaded Net < op call
[op_overload.vv:10] 'overloaded Addr < op call': overloaded Addr < op call
[op_overload.vv:31] 'overloaded Net == op call': overloaded Net == op call

Output if assert a > b is uncommented:

op_overload.vv:40:11: error: only `==` and `!=` are defined on arrays
   38 |     
   39 |     assert a != b
   40 |     assert a > b // but doesn't works here
      |              ^
   41 |     
   42 |     net_a := Net{a, 24}

Expected Behavior

I expect to >, <, <= and >= works for my Addr type, i.e. the following code should work:

import encoding.binary

type Addr = [4]u8

fn (a Addr) u32() u32 {
	return binary.big_endian_u32_fixed(a)
}

fn (a Addr) < (b Addr) bool {
	dump('overloaded Addr < op call')
	return a.u32() < b.u32()
}

fn main() {
	a := Addr([u8(1), 2, 3, 4]!)
	b := Addr([u8(5), 4, 3, 2]!)
	
	assert a != b
	assert a > b
}

This behavior does not violate the restrictions described in https://docs.vlang.io/limited-operator-overloading.html#restriction

Current Behavior

Checker forbids anything except == and !=.

Possible Solution

No response

Additional Information/Context

No response

V version

V 0.4.8 939d243

Environment details (OS name and version, etc.)

V full version: V 0.4.8 5ec9bb5.939d243
OS: linux, Linux version 6.6.8-arch1-1 (linux@archlinux) (gcc (GCC) 13.2.1 20230801, GNU ld (GNU Binutils) 2.41.0) #1 SMP PREEMPT_DYNAMIC Thu, 21 Dec 2023 19:01:01 +0000
Processor: 16 cpus, 64bit, little endian, 12th Gen Intel(R) Core(TM) i5-1240P

getwd: /home/ge
vexe: /home/ge/.vlang/v
vexe mtime: 2024-12-19 18:01:34

vroot: OK, value: /home/ge/.vlang
VMODULES: OK, value: /home/ge/.vmodules
VTMP: OK, value: /tmp/v_1000

Git version: git version 2.47.1
Git vroot status: weekly.2024.51-22-g939d243b (1 commit(s) behind V master)
.git/config present: true

CC version: cc (GCC) 14.2.1 20240910
emcc version: N/A
thirdparty/tcc status: thirdparty-linux-amd64 0134e9b9

Note

You can use the 👍 reaction to increase the issue's priority for developers.

Please note that only the 👍 reaction to the issue itself counts as a vote.
Other reactions and those to comments will not be taken into account.

Huly®: V_0.6-21649

@gechandesu gechandesu added the Bug This tag is applied to issues which reports bugs. label Dec 19, 2024
@jorgeluismireles
Copy link

op_overload.vv:40:11: error: only == and != are defined on arrays

I didn't know about this restriction but imho I like it and I think I understand it. Complex numbers are two dimensional numbers. You can't say if one complex number is greater than other but only if they are exactly equal or not. Arrays to me could represent multi dimensional numbers so also only == and != make sense. Rearranging the array in little or big endian should not be the reason to extends the comparison of > family. But what I want to know is to see a conclusion for this issue.

@gechandesu
Copy link
Contributor Author

I thought about this some more. I agree with jorgeluismireles. It seems that arrays really should support only == and !=.

Initially, I didn't even think about adding additional operators for regular arrays. But I would like to be able to do this for their aliases through operator overloading. Maybe I'm wrong and it won't work. If so, it seems strange that < worked in the case where the array alias is a struct field.

In any case, even if this issue is rejected, I can simply add lt(), le(), gt(), ge() methods for the type alias and solve the problem that way. Using operator overloading here would be nice and more readable.

@JalonSolov
Copy link
Contributor

The problem is in understanding what should happen if the operators are overloaded.

For example arr1 < arr2... does that mean every element in arr1 is less than the corresponding element in arr2?

Or does it mean every element in arr1 is less than at least one element of arr2?

What if the array sizes are different?

Is the shorter array "less than" the longer array?

What if all the elements of the longer array are less than the smallest element of the other array?

I could go on for a long time about all the possible items of confusion. == and != are easy - either all the elements match, or they don't. With other operators, the possibilities expand almost exponentially.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug This tag is applied to issues which reports bugs.
Projects
None yet
Development

No branches or pull requests

3 participants