V version: V 0.1.30 5e59718.bac6be2
OS: Linux version 5.4.72-gentoo (root@plasma) (gcc version 9.3.0 (Gentoo 9.3.0-r1 p3))
What did you do?
struct Dog {}
struct Cat {}
fn (d Dog) speak() { println('woof') }
fn (c Cat) speak() { println('meow') }
type Pet = Dog | Cat
fn (mut p Pet) speak() {
println('Speak')
match p {
Dog { p.speak() }
Cat { p.speak() }
}
}
fn main() {
mut pet := Pet(Cat{})
pet.speak()
}
What did you expect to see?
No problem in matching types of Pet.speak() with 'mu p' and with 'p' vars
What did you see instead?
Infinite loop with final segment fault!
Work fine when I remove the 'mut' in
fn (mut p Pet) speak() {
Also work if I use (but perhaps fail if the fn has parameters):
fn (mut p Pet) speak() {
println('Speak')
match p {
Dog { (p as Dog).speak() }
Cat { (p as Cat).speak() }
}
}
hi @ejtizado I have added a fix so that mut receiver can be used in 44b9ea4 however the match will need to have mut eg:
struct Dog {}
struct Cat {}
fn (d Dog) speak() { println('woof') }
fn (c Cat) speak() { println('meow') }
type Pet = Dog | Cat
fn (mut p Pet) speak() {
println('Speak')
match mut p {
Dog { p.speak() }
Cat { p.speak() }
}
}
fn main() {
mut pet := Pet(Cat{})
pet.speak()
}
If the receiver/var is mut and the match does not have mut then the smartcast will never occur so you will be calling Pet.speak() in an infinite loop. I'm not sure if we need to handle this any differently in the future
As you say it must be work (receiver and sender with mut), but also result in an infinite loop!
struct Dog {}
struct Cat {}
fn (mut d Dog) speak() { println('woof') }
fn (mut c Cat) speak() { println('meow') }
type Pet = Dog | Cat
fn (mut p Pet) speak() {
println('Speak')
match p {
Dog { p.speak() }
Cat { p.speak() }
}
}
fn main() {
mut pet := Pet(Cat{})
pet.speak()
}
In my program 'Pet' is a Database and Dog (NoSql) and Cat (Sql) engines. Logically I need a mut Database to speak (Open).
I think would be the smartcast in this case would be of interest
@ejtizado you need match mut p because otherwise the smart cast is never performed which means p is the sum type Pet not Cat or Dog. So its an infinite loop of Pet.speak() which calls itself
You can see the condition which activates the smart cast here: https://github.com/vlang/v/blob/master/vlib/v/checker/checker.v#L3643. It could be that this needs more consideration.
I'm opening this again for now, as this behaviour is unclear and this may need more discussion
Thanks @joe-conigliaro . After update V it works fine.
Only an advise on the behaviour (as you say unclear). This also work:
struct Dog {}
struct Cat {}
fn (mut d Dog) speak() { println('woof') }
fn (mut c Cat) speak() { println('meow') }
type Pet = Dog | Cat
fn (p Pet) speak() {
println('Speak')
match mut p {
Dog { p.speak() }
Cat { p.speak() }
}
}
fn main() {
mut pet := Pet(Cat{})
pet.speak()
}
it doesn't make sense that 'fn (p Pet)' is inmutable and then 'match' mark as mutable and send as mutable to Doc/Cat. speak()
No problem @ejtizado, thanks for bringing the issue to our attention.
You are correct about your previous comment, the compiler will need to error in this condition. I will get this sorted out.
Most helpful comment
Thanks @joe-conigliaro . After update V it works fine.
Only an advise on the behaviour (as you say unclear). This also work:
it doesn't make sense that 'fn (p Pet)' is inmutable and then 'match' mark as mutable and send as mutable to Doc/Cat. speak()