Printing one and the same object in different places gives different output

I have a graph, where nodes are words (type ** Word **) and edges are replace rules, that make one word from another. For example betwen 123 and333 nodes there is a 12-> 33 edge.

To find all patches from one word to another I have a function FindPath:

func (this *Graph) FindPath(from Word, to Word, visited Dict, current Path) {
    if from.Eq(to) {
        if len(this.Pathes) == 0 {
            fmt.Println(current)
        }

        this.Pathes = append(this.Pathes, current)
        return
    }

    if visited.Index(from) != -1 { // если уже были в этом узле
        return
    }

    index := this.nodes.Index(from)

    if index == -1 {
        return
    }

    for r := 0; r < len(this.rules); r++ {
        index := from.Index(this.rules[r].Pat)

        if index == -1 {
            continue
        }

        this.FindPath(from.ApplyRule(this.rules[r]), to, append(visited, from), append(current, this.rules[r]))
    }

    return
}

After FindPath is called, all pathes should be stored in this.Pathes, but appart from true pathes there are some false ones.

To see that you can add these lines between lines 2 and 3

if len(this.Pathes) == 0 {
     fmt.Println(current)
}

and also this line in the main function. FindPath is called:

g.FindPath(Word {1, 0, 1}, Word {1, 1}, nil, nil)
fmt.Println(g.Pathes [0]) // this one

And if you run it, you will get this output:

 [{[1 0 1] [0]} {[0] [1]} {[1] [1 0]} {[1 0] [1 1]}] // .FindPath, right one
 [{[1 0 1] [0]} {[0] [1]} {[1] [1 0]} {[1 0] [1 1 1]}] // main, false

What am I doing wrong? Why can one and the same object change it`s value? How shoud I fix it?

I can post more code (all of it), but i belive, that the problem is here.

Thank you in advance.

Unclear, because we don’t see the definition of Path nor how they are allocated and passed around, and cannot run it to check. Post a runnable example showing the issue and we can see.

Sometimes, this kind of problem is caused by reusing slices improperly.


Edit: Ah, yes.

this.FindPath(from.ApplyRule(this.rules[r]), to, append(visited, from), append(current, this.rules[r]))

In append(current, this.rules[r]) you are creating a new slice from current with an element appended. Lets say current was [a, b] and now it becomes [a, b, c]. This happens in a loop. Next iteration might append d instead to make [a, b, d]. But the two slices share the same backing array, so the previous iteration’s [a, b, c] now gets overwritten to [a, b, d].

You’ll want to make copies of current and other similar slice things when they are duplicated like this and are intended to both live separate lives afterwards. The append function may make a copy of the backing array, but usually it will not need to.

nextCurrent := make([]whatever, len(current))
copy(nextCurrent, current)

Apply as necessary to other parts of the same program if it applies (e.g., visited), as it looks like you have slices of objects with slices in them - copying one of those objects is a “shallow” copy in the same way.

See: https://blog.golang.org/go-slices-usage-and-internals

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.