package main

import "fmt"

// Berlabel: interface biasa yang hanya berisi method set.
type Berlabel interface {
	String() string
}

// Bilangan: constraint dengan union dua elemen tilde.
type Bilangan interface {
	~int | ~float64
}

// Skor: tipe dengan underlying int sekaligus method String.
type Skor int

func (s Skor) String() string {
	return fmt.Sprintf("skor %d", int(s))
}

// BulatBerlabel adalah irisan: underlying int DAN memiliki method String.
type BulatBerlabel interface {
	Berlabel
	~int
}

// Operator aritmetika sah karena seluruh anggota himpunan ber-underlying int.
func Naikkan[L BulatBerlabel](nilai L) L {
	return nilai + 1
}

// Operator tambah sah untuk seluruh anggota himpunan Bilangan.
func Gabung[B Bilangan](a, b B) B {
	return a + b
}

// Tempel memakai union int | string tanpa tilde.
// Operator + sah karena berlaku untuk int maupun string.
func Tempel[T int | string](a, b T) T {
	return a + b
}

func main() {
	var ujian Skor = 87
	naik := Naikkan(ujian)
	fmt.Println(naik.String())

	fmt.Println(Gabung(10, 32))
	fmt.Println(Gabung(1.5, 2.25))

	fmt.Println(Tempel(10, 32))
	fmt.Println(Tempel("go", "lang"))
}
