Skip to content

proposal: new builtin to pick from one of two values #36303

Closed
@mdevan

Description

@mdevan

Consider a builtin called pick that can pick from one of two given values of the same type, depending on a boolean expression:

// before
var v string
if expr {
    v = "value1"
} else {
    v = "value2"
}

// after
v := pick(expr, "value1", "value2")

Yes, it is yet another ternary operator proposal :-), but this time suggested as a builtin similar to append or delete.

The signature of pick would look like:

func pick(cond bool, lhs, rhs Type) Type

where Type is any(?) type and the compiler would enforce that lhs, rhs and the return value are of the same type - similar to how the 2nd and later arguments of append and the return value are of the same type.

Only one of the arguments would be evaluated depending on the result of the boolean expression, similar to an if-else statement.

As for evidence that this can simplify code, here are some examples, all taken from the single Go source code file fmt/format.go:

lines 76-80:

// before
	// Decide which byte the padding should be filled with.
	padByte := byte(' ')
	if f.zero {
		padByte = byte('0')
	}

// after
    padByte := byte(pick(f.zero, '0', ' '))

lines 124-132:

// before
func (f *fmt) fmtBoolean(v bool) {
	if v {
		f.padString("true")
	} else {
		f.padString("false")
	}
}

// after
func (f *fmt) fmtBoolean(v bool) {
    f.padString(pick(v, "true", "false"))
}

lines 370-374:

// before
	length := len(b)
	if b == nil {
		// No byte slice present. Assume string s should be encoded.
		length = len(s)
	}

// after
    length := pick(b == nil, len(s), len(b))

lines 419-423:

// before
		if b != nil {
			c = b[i] // Take a byte from the input byte slice.
		} else {
			c = s[i] // Take a byte from the input string.
		}

// after
    c = pick(b != nil, b[i], s[i])

lines 454-458, also lines 481-485:

// before
	if f.plus {
		f.pad(strconv.AppendQuoteToASCII(buf, s))
	} else {
		f.pad(strconv.AppendQuote(buf, s))
	}

// after
    f.pad(pick(f.plus, strconv.AppendQuoteToASCII(buf, s), strconv.AppendQuote(buf, s))

lines 464-467, also lines 476-479:

// before
	r := rune(c)
	if c > utf8.MaxRune {
		r = utf8.RuneError
	}

// after
    r := pick(c > utf8.MaxRune, utf8.RuneError, rune(c))

lines 526-531:

// before
			digits = prec
			// If no precision is set explicitly use a precision of 6.
			if digits == -1 {
				digits = 6
			}

// after
    digits = pick(digits == -1, 6, prec)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions