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

Sorting an array of references #21662

Closed
pd-giz-dave opened this issue Jun 10, 2024 · 9 comments · Fixed by #21706
Closed

Sorting an array of references #21662

pd-giz-dave opened this issue Jun 10, 2024 · 9 comments · Fixed by #21706
Labels
Bug This tag is applied to issues which reports bugs.

Comments

@pd-giz-dave
Copy link

pd-giz-dave commented Jun 10, 2024

Describe the bug

Source does not compile

Reproduction Steps

Attempt to compile this:

module main

// sorting an array of references
// get compiler error:  sort_with_compare callback function parameter `a` with type `&Thing` should be `&&Thing`
// but 'a' is defined as &&

type Thing = int

struct Things {
mut:
	items []&Thing
}

fn (mut t Things) sort() {
	t.items.sort_with_compare(fn (mut a &&Thing, mut b &&Thing) int {return 0})
	//                                  ^^             ^^
}

fn main() {
	mut t := Things{}
	t.sort()
}

Expected Behavior

It should compile

Current Behavior

Get error: sort_with_compare callback function parameter a with type &Thing should be &&Thing

Possible Solution

I could not find a workaround

Additional Information/Context

No response

V version

V 0.4.6 100b3b0

Environment details (OS name and version, etc.)

V full version: V 0.4.6 294f7e4.100b3b0
OS: linux, "EndeavourOS Linux"
Processor: 16 cpus, 64bit, little endian, AMD Ryzen 7 5800H with Radeon Graphics

getwd: /home/dave
vexe: /home/dave/v/v
vexe mtime: 2024-06-10 18:48:53

vroot: OK, value: /home/dave/v
VMODULES: OK, value: /home/dave/.vmodules
VTMP: OK, value: /tmp/v_1000

Git version: git version 2.45.1
Git vroot status: weekly.2024.14-438-g100b3b0f
.git/config present: true

CC version: cc (GCC) 14.1.1 20240507
thirdparty/tcc status: thirdparty-linux-amd64 40e5cbb5

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.

@pd-giz-dave pd-giz-dave added the Bug This tag is applied to issues which reports bugs. label Jun 10, 2024
@spytheman
Copy link
Member

Use t.items.sort_with_compare(fn (a &&Thing, b &&Thing) int {return 0})

@pd-giz-dave
Copy link
Author

Just remove the mut - doh - the compiler error message is very confusing
I'm guessing its because a mut implies a reference
Thanks for the workaround

@pd-giz-dave
Copy link
Author

Unfortunately removing the mut in my context does not work, consider this extended example (a distillation of my real case):

module main
// sorting an array of mutable references
struct Thing {
mut:
	a int = 2
	b int = 4
	av int = 0
}
fn (mut t Thing) average() int {
	t.av = (t.a + t.b) / 2
	return t.av
}
struct Things {
mut:
	items []&Thing
}
fn (mut t Things) sort() {
	t.items.sort_with_compare(fn (a &&Thing, b &&Thing) int {
		if a.average() > b.average() {
			return 1
		} else if a.average() < b.average() {
			return -1
		}
		return 0
	})
}
fn main() {
	mut t := Things{}
	t.sort()
}

My real context is a lot more complex, but the above illustrates the problem. There is a conflict with 'mut' and the result is un-compilable, getting an error of:

compiler_bugs/main.v:19:6: error: the closure copy of `a` is immutable, declare it with `mut` to make it mutable
   17 | fn (mut t Things) sort() {
   18 |     t.items.sort_with_compare(fn (a &&Thing, b &&Thing) int {
   19 |         if a.average() > b.average() {
      |            ^

How do I get over this?

@pd-giz-dave
Copy link
Author

pd-giz-dave commented Jun 18, 2024 via email

@JalonSolov
Copy link
Contributor

Yes, notifications are still sent (and seen) even if the issue has been closed. You did nothing "wrong". Perhaps it would be more "correct" to re-open the issue if you're still having problems.

@JalonSolov JalonSolov reopened this Jun 18, 2024
@yuyi98
Copy link
Member

yuyi98 commented Jun 20, 2024

struct Thing {
mut:
	a int = 2
	b int = 4
	av int
}

fn (mut t Thing) average() int {
	t.av = (t.a + t.b) / 2
	return t.av
}

struct Things {
mut:
	items []&Thing
}

fn (mut t Things) sort() {
	t.items.sort_with_compare(fn (a &&Thing, b &&Thing) int {
		if (*a).average() > (*b).average() {
			return 1
		} else if (*a).average() < (*b).average() {
			return -1
		}
		return 0
	})
}

fn main() {
	mut t := Things{}
	t.items << &Thing{1, 2, 0}
	t.items << &Thing{5, 7, 0}
	t.items << &Thing{2, 4, 0}
	t.sort()
	println(t)
}

PS D:\Test\v\tt1> v run .
Things{
    items: [&Thing{
    a: 1
    b: 2
    av: 1
}, &Thing{
    a: 2
    b: 4
    av: 3
}, &Thing{
    a: 5
    b: 7
    av: 6
}]
}

@pd-giz-dave
Copy link
Author

Thanks for the workaround. De-referencing works, but why?
In V, variables are immutable by default, so I would expect the compiler to complain when average() is called with an immutable variable when its expecting a mutable one.
Or are the rules different when dealing with references?
I'm confused.
To make it more obvious I did this:

fn (mut t Things) sort() {
	t.items.sort_with_compare(fn (a &&Thing, b &&Thing) int {
		mut ma := *a
		mut mb := *b
		if ma.average() > mb.average() {
			return 1
		} else if ma.average() < mb.average() {
			return -1
		}
		return 0
	})
}

But by my niaive understanding of V I'd expect this to work:

fn (mut t Things) sort() {
	t.items.sort_with_compare(fn (mut a &Thing, mut b &Thing) int {
		if a.average() > b.average() {
			return 1
		} else if a.average() < b.average() {
			return -1
		}
		return 0
	})
}

Or at least provide a more helpful compiler error.

@spytheman
Copy link
Member

btw, sorting with a comparison function, that modifies the compared items, is imho asking for trouble in general, since you do not know in advance on which items it will be called, how many times, etc.

@pd-giz-dave
Copy link
Author

btw, sorting with a comparison function, that modifies the compared items, is imho asking for trouble in general, since you do not know in advance on which items it will be called, how many times, etc.

The real 'average' function that highlighted this issue calculates something that is expensive, so its evaluation is 'lazy', done on demand on the first call, once calculated it never changes. The sort algorithm calls it multiple times. The real application may, or may not, call it depending on context. I think that is a legitimate use case.

But thanks for the speedy fix. I continue to be impressed...

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

Successfully merging a pull request may close this issue.

4 participants