Skip to content

Instantly share code, notes, and snippets.

@thanhminhmr
Last active March 28, 2025 12:34
Show Gist options
  • Save thanhminhmr/05593d24fd3ee533e5e1970ea82e3952 to your computer and use it in GitHub Desktop.
Save thanhminhmr/05593d24fd3ee533e5e1970ea82e3952 to your computer and use it in GitHub Desktop.
Go doesn't have ternary, so created one...

go-ternary

Yes, I know—yet another attempt at bringing a ternary-like experience to Go. But hey, Go doesn’t have one, and I wasn’t around when the last million were written.

Why?

Because Go doesn't have a ternary operator, and according to the official FAQ, it likely never will. The reasoning? To prevent developers from writing "impenetrably complex expressions." But let's be real—poor coding practices exist in all forms. Instead of outright banning a useful construct, wouldn’t compiler warnings for overly complicated ternary expressions have been a more reasonable approach?

Since that's not happening, here’s go-ternary—because sometimes, a one-liner is just nicer than an if-else.

package ternary
func If[T any](condition bool, ifTrue Supplier[T], ifFalse Supplier[T]) T {
if condition {
return ifTrue.Get()
}
return ifFalse.Get()
}
func Func[T any](supplier func() T) Supplier[T] {
return FuncSupplier[T](supplier)
}
func Value[T any](value T) Supplier[T] {
return ValueSupplier[T]{Value: value}
}
type Supplier[T any] interface {
Get() T
}
type FuncSupplier[T any] func() T
func (s FuncSupplier[T]) Get() T {
return s()
}
type ValueSupplier[T any] struct {
Value T
}
func (s ValueSupplier[T]) Get() T {
return s.Value
}
package ternary
import "testing"
func assertEquals[T comparable](t *testing.T, a T, b T) {
if a != b {
t.Errorf("assertEquals failed: %v != %v", a, b)
}
}
func Test(t *testing.T) {
assertEquals(t, If(true, Value("true"), Value("false")), "true")
assertEquals(t, If(false, Value("true"), Value("false")), "false")
assertEquals(t, If(true, Func(func() string {
return "true"
}), Func(func() string {
t.Error("lazyEvaluate failed: this func should not be called")
return "false"
})), "true")
assertEquals(t, If(false, Func(func() string {
t.Error("lazyEvaluate failed: this func should not be called")
return "true"
}), Func(func() string {
return "false"
})), "false")
}
@thanhminhmr
Copy link
Author

Imagine stacking it... If(a > b, if(c > d, true, false), false)

Let me imagine it for you...

func dayInWeek(days int) string {
    dayInWeek := days / 7
    return If(
        dayInWeek == 0,
        Value("Sunday"),
        Func(func() string {
            return If(
                dayInWeek == 1,
                Value("Monday"),
                Func(func() string {
                    return If(
                        dayInWeek == 2,
                        Value("Tuesday"),
                        Func(func() string {
                            return If(
                                dayInWeek == 3,
                                Value("Wednesday"),
                                Func(func() string {
                                    return If(
                                        dayInWeek == 4,
                                        Value("Thursday"),
                                        Func(func() string {
                                            return If(
                                                dayInWeek == 5,
                                                Value("Friday"),
                                                Func(func() string {
                                                    return If(
                                                        dayInWeek == 6,
                                                        Value("Saturday"),
                                                        Func(func() string {
                                                            panic("unreachable")
                                                        }),
                                                    )
                                                }),
                                            )
                                        }),
                                    )
                                }),
                            )
                        }),
                    )
                }),
            )
        }),
    )
}

@IngwiePhoenix
Copy link

Perfection. x)

@cbrgm
Copy link

cbrgm commented Mar 25, 2025

Finally, a ternary so clean, even Go’s compiler will need therapy.

@threevi
Copy link

threevi commented Mar 25, 2025

It’s unquestionably beautiful.

@aflansburg
Copy link

I remember probably 7-8 years ago the JS guru Eric Elliot had an article titled "Nested Ternaries are great".
Then I saw one in the wild in a React component not too long after.
It was daisy chained from here to infinity and beyond into the abyss.

I could but only catch a glimpse of the very last : as it fell into the event horizon.

Such beauty.
Such sadness.

In late 2021, it was raining - cold outside - I was bored. Opened my browser and started surfing.
Found an article about clean code and the author, another respected JS guru, was begging people:
"Please stop nesting ternaries."

I shall nest this ternary however. It begs me thus to travel into yon abyss.

@leoantony72
Copy link

😭

@sunderee
Copy link

Perfection.

@matjam
Copy link

matjam commented Mar 27, 2025

I've improved it

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

var ternaryRegex = regexp.MustCompile(`(?m)^(\s*)(\w+)\s*(:=|=)\s*([^?]+)\?\s*([^:]+):\s*(.+)$`)

func main() {
	if len(os.Args) < 2 {
		fmt.Fprintln(os.Stderr, "Usage: goternary input.go2")
		os.Exit(1)
	}

	inputPath := os.Args[1]
	if !strings.HasSuffix(inputPath, ".go2") {
		fmt.Fprintf(os.Stderr, "Input file must have .go2 extension: %s\n", inputPath)
		os.Exit(1)
	}

	content, err := os.ReadFile(inputPath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to read input file: %v\n", err)
		os.Exit(1)
	}

	processed := processTernary(string(content))
	processed = ensureTernaryImport(processed)
	output := addGeneratedHeader(processed)

	outputPath := strings.TrimSuffix(inputPath, ".go2") + ".go"
	err = os.WriteFile(outputPath, []byte(output), 0644)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to write output file: %v\n", err)
		os.Exit(1)
	}
}

func processTernary(src string) string {
	var buf bytes.Buffer
	scanner := bufio.NewScanner(strings.NewReader(src))
	for scanner.Scan() {
		line := scanner.Text()
		match := ternaryRegex.FindStringSubmatch(line)
		if match != nil {
			// match[1] = indent, match[2] = var name, match[3] = := or =, match[4] = condition, match[5] = trueExpr, match[6] = falseExpr
			indent := match[1]
			varName := match[2]
			op := match[3]
			cond := strings.TrimSpace(match[4])
			trueVal := strings.TrimSpace(match[5])
			falseVal := strings.TrimSpace(match[6])
			newLine := fmt.Sprintf("%s%s %s ternary.If(%s, ternary.Value(%s), ternary.Value(%s))", indent, varName, op, cond, trueVal, falseVal)
			buf.WriteString(newLine + "\n")
		} else {
			buf.WriteString(line + "\n")
		}
	}
	return buf.String()
}

func ensureTernaryImport(src string) string {
	lines := strings.Split(src, "\n")
	inImport := false
	foundImport := false
	for i, line := range lines {
		if strings.HasPrefix(line, "import (") {
			inImport = true
			continue
		}
		if inImport {
			if line == ")" {
				if !foundImport {
					lines = append(lines[:i], append([]string{"\t\"ternary\""}, lines[i:]...)...)
				}
				break
			}
			if strings.Contains(line, "\"ternary\"") {
				foundImport = true
			}
		}
	}
	return strings.Join(lines, "\n")
}

func addGeneratedHeader(src string) string {
	header := "// Code generated by goternary; DO NOT EDIT.\n"
	header += fmt.Sprintf("// Source: %s\n\n", filepath.Base(os.Args[1]))
	return header + src
}

given an input file of test.go2

package main

import (
	"fmt"
)

func main() {
	a := 1
	b := 2

	c := a == b ? "a is equal to b" : "a is not equal to b"

	fmt.Println(c)
}

it will generate test.go

// Code generated by goternary; DO NOT EDIT.
// Source: test.go2

package main

import (
	"fmt"
	"ternary"
)

func main() {
	a := 1
	b := 2

	c := ternary.If(a == b, ternary.Value("a is equal to b"), ternary.Value("a is not equal to b"))

	fmt.Println(c)
}

We might be onto something! We can just do what the javascript kids do. When the language doesn't support the thing they want, they just add it with a transpiler and call it something else!

Maybe go2 is on the nose but they did say they'll never release go2, so maybe we go add generic methods while we're at it.

@matjam
Copy link

matjam commented Mar 27, 2025

its not recursive tho, thats a .go3 feature

@oneEyedSunday
Copy link

I remember probably 7-8 years ago the JS guru Eric Elliot had an article titled "Nested Ternaries are great". Then I saw one in the wild in a React component not too long after. It was daisy chained from here to infinity and beyond into the abyss.

I could but only catch a glimpse of the very last : as it fell into the event horizon.

Such beauty. Such sadness.

In late 2021, it was raining - cold outside - I was bored. Opened my browser and started surfing. Found an article about clean code and the author, another respected JS guru, was begging people: "Please stop nesting ternaries."

I shall nest this ternary however. It begs me thus to travel into yon abyss.

poetry in motion

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment