Method call behavior in Go - Time & Space Complexity
When we call a method in Go, it runs some code. We want to know how the time it takes changes as the input grows.
How does calling a method affect the total work done by the program?
Analyze the time complexity of the following code snippet.
package main
import "fmt"
type Counter struct {
count int
}
func (c *Counter) Increment(n int) {
for i := 0; i < n; i++ {
c.count++
}
}
func main() {
c := Counter{}
c.Increment(100)
fmt.Println(c.count)
}
This code defines a method Increment that adds 1 to count n times. We call it with n = 100.
- Primary operation: The for loop inside the Increment method that runs c.count++ repeatedly.
- How many times: The loop runs exactly n times, where n is the input to Increment.
As n grows, the number of times we add to count grows the same way.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 increments |
| 100 | 100 increments |
| 1000 | 1000 increments |
Pattern observation: The work grows directly with n. Double n, double the work.
Time Complexity: O(n)
This means the time to run the method grows in a straight line with the input size n.
[X] Wrong: "Calling a method always takes the same time no matter what."
[OK] Correct: The method here has a loop that runs n times, so bigger n means more work and more time.
Understanding how method calls affect time helps you explain your code clearly and shows you know what happens inside your functions.
"What if the Increment method called another method inside the loop? How would that change the time complexity?"
Practice
Solution
Step 1: Understand value receiver behavior
Methods with value receivers get a copy of the variable, not the original.Step 2: Effect on original variable
Since the method works on a copy, changes inside the method do not affect the original variable.Final Answer:
The method works on a copy of the variable, so original data is not changed. -> Option BQuick Check:
Value receiver = copy, no original change [OK]
- Thinking value receivers modify original data
- Confusing pointer and value receivers
- Assuming method call causes error
Solution
Step 1: Recall pointer receiver syntax
Pointer receivers are declared as (variable *Type) before method name.Step 2: Match correct syntax
func (p *Person) UpdateName(newName string) {} matches the correct syntax: func (p *Person) MethodName(params) {}.Final Answer:
func (p *Person) UpdateName(newName string) {} -> Option AQuick Check:
Pointer receiver syntax = (p *Type) [OK]
- Placing * after type name incorrectly
- Using * before method name
- Confusing pointer receiver with pointer return type
package main
import "fmt"
type Counter struct { count int }
func (c Counter) Increment() { c.count++ }
func (c *Counter) IncrementPtr() { c.count++ }
func main() {
c := Counter{count: 5}
c.Increment()
fmt.Println(c.count)
c.IncrementPtr()
fmt.Println(c.count)
}Solution
Step 1: Analyze Increment method call
Increment has a value receiver, so c.count++ modifies a copy, original c.count remains 5.Step 2: Analyze IncrementPtr method call
IncrementPtr has a pointer receiver, so c.count++ modifies original c.count, changing it from 5 to 6.Final Answer:
5\n6 -> Option DQuick Check:
Value receiver no change, pointer receiver changes original [OK]
- Assuming value receiver changes original
- Confusing method call effects
- Ignoring pointer receiver behavior
type Item struct { value int }
func (i Item) SetValue(v int) { i.value = v }
func main() {
item := Item{value: 10}
item.SetValue(20)
fmt.Println(item.value)
}Solution
Step 1: Check method receiver type
SetValue uses a value receiver, so it works on a copy of item.Step 2: Effect on original item
Changes inside SetValue do not affect original item.value, so it remains 10.Final Answer:
SetValue method uses a value receiver, so item.value is not updated. -> Option AQuick Check:
Value receiver means no original update [OK]
- Assuming pointer receiver is mandatory for compilation
- Thinking method return needed to update value
- Ignoring import fmt requirement (not shown here)
package main
import "fmt"
type Number struct { n int }
func (num Number) Double() Number { num.n *= 2; return num }
func (num *Number) Triple() { num.n *= 3 }
func main() {
x := Number{n: 2}
y := x.Double()
y.Triple()
fmt.Println(x.n, y.n)
}Solution
Step 1: Call x.Double()
Double has a value receiver, so it works on a copy of x, doubles n from 2 to 4, and returns it as y.Step 2: Call y.Triple()
Triple has a pointer receiver, so it modifies y.n in place, tripling 4 to 12.Step 3: Print values
x.n remains 2 (unchanged), y.n is 12 after doubling then tripling.Final Answer:
2 12 -> Option CQuick Check:
Value receiver returns copy doubled, pointer receiver modifies copy [OK]
- Assuming x.n changes after Double()
- Confusing which variable is modified by Triple()
- Ignoring return value from Double()
Ready to prove it?
Pass the test and this pattern moves unknown
