Menu
Coddy logo textTech

Method Chaining

Part of the Object Oriented Programming section of Coddy's GO journey — lesson 81 of 107.

Method chaining is a technique where methods return the receiver, allowing multiple method calls to be linked together in a single statement. You've already seen this in the Builder pattern, but it's a standalone concept useful in many contexts.

The key is returning a pointer to the struct from each method:

type Query struct {
    table   string
    columns []string
    where   string
    limit   int
}

func (q *Query) Select(cols ...string) *Query {
    q.columns = cols
    return q
}

func (q *Query) From(table string) *Query {
    q.table = table
    return q
}

func (q *Query) Where(condition string) *Query {
    q.where = condition
    return q
}

func (q *Query) Limit(n int) *Query {
    q.limit = n
    return q
}

Now you can chain these calls fluently:

query := &Query{}
query.Select("name", "email").From("users").Where("active = true").Limit(10)

This reads almost like natural language compared to separate statements. Method chaining works best when operations configure or modify an object without needing to return other values. It's commonly used in query builders, configuration APIs, and test assertion libraries.

Remember that each method must use a pointer receiver and return *StructType for the chain to work properly.

challenge icon

Challenge

Easy

Let's build a fluent HTML element builder that uses method chaining to construct HTML tags with attributes and content! This is a practical application of method chaining—you'll create an API that reads almost like natural language when building HTML elements.

You'll organize your code across two files:

  • element.go: Define your HTML element builder with chainable methods.

    Create an Element struct that stores the tag name, a map of attributes (string to string), and the inner content. Build these chainable methods that each return *Element:

    • NewElement(tag string) - constructor that creates a new Element with the given tag name and an initialized (empty) attributes map
    • Attr(key, value string) - adds an attribute to the element
    • ID(id string) - convenience method that sets the "id" attribute
    • Class(class string) - convenience method that sets the "class" attribute
    • Content(text string) - sets the inner content of the element

    Add a Render() method that returns the HTML string. Attributes should appear in alphabetical order by key. The format is:

    <tag attr1="value1" attr2="value2">content</tag>

    If there are no attributes, just render <tag>content</tag>. If there's no content, render <tag attr="value"></tag>.

  • main.go: Build HTML elements using method chaining.

    Read the tag name, then read a count of operations to perform. Each operation is one of:

    • id followed by the ID value
    • class followed by the class value
    • attr followed by the attribute name and value (two lines)
    • content followed by the content text

    Chain all operations together fluently, then print the rendered HTML.

The following inputs will be provided:

  • Line 1: Tag name
  • Line 2: Number of operations
  • Following lines: Operation type and value(s)

For example, given:

div
3
id
container
class
main-content
content
Hello World

Your output should be:

<div class="main-content" id="container">Hello World</div>

And given:

a
3
attr
href
https://example.com
attr
target
_blank
content
Click here

Your output should be:

<a href="https://example.com" target="_blank">Click here</a>

And given:

input
2
attr
type
text
attr
placeholder
Enter name

Your output should be:

<input placeholder="Enter name" type="text"></input>

And given:

p
1
content
Simple paragraph

Your output should be:

<p>Simple paragraph</p>

Notice how method chaining lets you build elements step by step in a readable way. Each method modifies the element and returns it, allowing the next method call to be chained directly.

Cheat sheet

Method chaining is a technique where methods return the receiver (typically *StructType), allowing multiple method calls to be linked together in a single statement.

Each method must use a pointer receiver and return *StructType:

type Query struct {
    table   string
    columns []string
    where   string
    limit   int
}

func (q *Query) Select(cols ...string) *Query {
    q.columns = cols
    return q
}

func (q *Query) From(table string) *Query {
    q.table = table
    return q
}

func (q *Query) Where(condition string) *Query {
    q.where = condition
    return q
}

func (q *Query) Limit(n int) *Query {
    q.limit = n
    return q
}

Chain method calls fluently:

query := &Query{}
query.Select("name", "email").From("users").Where("active = true").Limit(10)

Method chaining works best when operations configure or modify an object without needing to return other values. It's commonly used in query builders, configuration APIs, and test assertion libraries.

Try it yourself

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)

	// Read tag name
	scanner.Scan()
	tagName := scanner.Text()

	// Read number of operations
	scanner.Scan()
	numOps, _ := strconv.Atoi(scanner.Text())

	// Create the element
	element := NewElement(tagName)

	// Process each operation
	for i := 0; i < numOps; i++ {
		scanner.Scan()
		operation := scanner.Text()

		// TODO: Based on the operation type, chain the appropriate method
		// Operations can be: "id", "class", "attr", or "content"
		// - For "id": read the next line as the ID value
		// - For "class": read the next line as the class value
		// - For "attr": read the next TWO lines (attribute name, then value)
		// - For "content": read the next line as the content text
		// Use method chaining to build the element fluently

		_ = operation // Remove this line when implementing
	}

	// Print the rendered HTML
	fmt.Println(element.Render())
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming