-3

Let's say I have a struct with state, and a few member functions on that struct. Let's say that the struct member returns an instance of its own type, and I call additional functions on that instance, and pass the result of calling some other member on the initial instance as an argument. Is the order of invocation between the first invocation, and the argument invocation, guaranteed?

(This pattern comes up a lot when trying to build "builder" type objects that have some internal state, like an expression stack.)

package main

import (
    "fmt"
)

type q struct {
    val int
}

func (s *q) getVal() int {
    return s.val
}

func (s *q) a() *q {
    s.val += 1
    return s
}

func (s *q) b(i int) int {
    return i + s.val
}

func main() {
    s := &q{}
    // this currently prints 2
    // but is that guaranteed?
    fmt.Println(s.a().b(s.getVal()))
}

Specifically, is the relative invocation order of s.a() versus s.getVal() guaranteed? Golang defines the "lexical left-to-right order," but only for an individual expression, and s.a().b() seems like it's technically a different expression than s.getVal().

The behavior it currently has is the behavior I'd want and expect, but I can't tell whether it's also a behavior I can rely on "forever."

blackgreen
  • 34,072
  • 23
  • 111
  • 129
Jon Watte
  • 6,579
  • 4
  • 53
  • 63
  • 1
    The spec is pretty easy to follow: https://golang.org/ref/spec#Order_of_evaluation – Jonathan Hall Feb 13 '20 at 21:13
  • 2
    The order of evaluation within one goroutine is guaranteed - I can't think of a language where it isn't. A program couldn't operate if the order of execution was unknown. – Adrian Feb 13 '20 at 21:13
  • 1
    Also the [Go 1 Compatibility Promise](https://golang.org/doc/go1compat) says programs that work today won't stop working under any version of Go 1.x. Changing order of evaluation behavior would obviously break that promise. – Adrian Feb 13 '20 at 21:16
  • @Adrian: Not _all_ aspects of the order of evaluation are guaranteed. See https://stackoverflow.com/q/34232126/13860 – Jonathan Hall Feb 13 '20 at 21:18
  • 2
    Though it's worth pointing out that any code that relies this heavily on order of evaluation is unnecessarily difficult to reason about by any developer reading it, and the design should be refactored to make it easier to comprehend and less error-prone. – Adrian Feb 13 '20 at 21:18
  • "programs that work today won't stop working under any version of Go 1.x" That's not exactly true. Some program that depends on an incidental feature of Go may stop working in the future. (Such as any program that relies on the precise order of a map, when this isn't guaranteed, for example.) – Jonathan Hall Feb 13 '20 at 21:18
  • 1
    Yes, but the entire document is too long to paste into a comment, *which is why I linked to it*. – Adrian Feb 13 '20 at 21:19
  • Adrian, I think you didn't understand the question. Also, I think you didn't understand the use case of "builder object" when you suggest refactoring. Obviously someone can rip every single part into SSA form but that's actually much more cumbersome to use. (This object is a helper on top of just such an interface.) – Jon Watte Feb 15 '20 at 21:06

1 Answers1

1

The relevant portion of the spec is:

all function calls, method calls, and communication operations are evaluated in lexical left-to-right order.

and

At package level, initialization dependencies override the left-to-right rule for individual initialization expressions, but not for operands within each expression:

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
  • Thanks Flimzy for confirming that the function call section still applies to different values that might to the compiler seem independent. That of course means there are tons of optimizations the compiler can't do, but that feels like the right trade-off for a language with arbitrary side effects. (This is why I generally prefer languages where ordering is either unimportant or explicit, like Haskell.) – Jon Watte Feb 15 '20 at 21:12