Repository: go
Issue: proposal: sync/v2: new package
Labels: v2,Proposal

### Proposal Details

The math/rand/v2 package has been successful. Let's consider another v2 package: sync/v2.

This is an update of #47657.

### Background

The current sync package provides `Map` and `Pool` types. These types were designed before Go supported generics. They work with values of type `any`.

Using `any` is not compile-time-type-safe. Nothing prevents using a key or value of any arbitrary type with a `sync.Map`. Nothing prevents storing a value of any arbitrary type into a `sync.Pool`. Go is in general a type-safe language. For all the reasons why Go map and slice types define the their key and element types, `sync.Map` and `sync.Pool` should as well.

Also, using `any` is inefficient. Converting a non-pointer value to `any` requires a memory allocation. This means that building a `sync.Map` with a key type of `string` requires an extra allocation for every value stored in the map. Storing a slice type in a `sync.Pool` requires an extra allocation.

These issues are easily avoided by changing `sync.Map` and `sync.Pool` to be generic types.

While we can't change `Map` and `Pool` to be generic in the current sync package because of compatibility concerns (see the discussion at #48287), we could consider adding new generic types to the existing sync package, as proposed at #47657. However, that will leave us with a confusing wart in the sync package that we can never remove. Having both `sync.Pool` and (say) `sync.PoolOf` is confusing. Deprecating `sync.Pool` still leaves us with a strange name for the replacement type.

Introducing a sync/v2 package will permit us to easily transition from the current package to a new package. It's true that future users will have to know to import "sync/v2" rather than "sync". However, few people write their own imports these days, and this transition is easily handled by goimports and similar tools.

### Proposal

In the sync/v2 package, the following types and functions will be the same as in the current sync package:

```Go
func OnceFunc(f func()) func()
func OnceValue[T any](f func() T) func() T
func OnceValues[T1, T2 any](f func() (T1, T2)) func() (T1, T2)
type Cond struct{ ... }
    func NewCond(l Locker) *Cond
type Locker interface{ ... }
type Mutex struct{ ... }
type Once struct{ ... }
type RWMutex struct{ ... }
type WaitGroup struct{ ... }
```

The existing `Map` type will be replaced by a new type that takes two type parameters. Note that the original `Range` method is replaced with an `All` method that returns an iterator.

```Go
// Map is like a Go map[K]V but is safe for concurrent use
// by multiple goroutines without additional locking or coordination.
// ...and so forth
type Map[K comparable, V any] struct { ... }

// Load returns the value stored in the map for a key, or the zero value if no
// value is present.
// The ok result indicates whether value was found in the map.
func (m *Map[K, V]) Load(key K) (value V, ok bool)

// Store sets the value for a key.
func (m *Map[K, V]) Store(key K, value V)

// LoadOrStore returns the existing value for the key if present.
// Otherwise, it stores and returns the given value.
// The loaded result is true if the value was loaded, false if stored.
func (m *Map[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool)

// LoadAndDelete deletes the value for a key, returning the previous value if any.
// The loaded result reports whether the key was present.
func (m *Map[K, V]) LoadAndDelete(key K) (value V, loaded bool)

// Delete deletes the value for a key.
func (m *Map[K, V]) Delete(key K)

// Swap swaps the value for a key and returns the previous value if any.
// The loaded result reports whether the key was present.
func (m *Map[K, V]) Swap(key K, value V) (previous V, loaded bool)

// CompareAndDelete deletes the entry for key if its value is equal to old.
// This panics if V is not a comparable type.
//
// If there is no current value for key in the map, CompareAndDelete
// returns false.
func (m *Map[K, V]) CompareAndDelete(key K, old V) (deleted bool)

// CompareAndSwap swaps the old and new values for key
// if the value stored in the map is equal to old.
// This panics if V is not a comparable type.
func (m *Map[K, V]) CompareAndSwap(key K, old, new V) (swapped bool)

// Clear deletes all the entries, resulting in an empty Map.
func (m *Map[K, V]) Clear()

// All returns an iterator over the keys and values in the map.
// ... and so forth
func (m *Map[K, V]) All() iter.Seq2[K, V]

// TODO: Consider Keys and Values methods that return iterators, like maps.Keys and maps.Values.
```

The existing `Pool` type will be replaced by a new type that takes a type parameter.

2025-01-04: The new version of `Pool` does not have an exported `New` field; instead, use `NewPool` to create a `Pool` that calls a function to return new values.

~~Note that the original `Get` method is replaced by one that returns two results, with the second being a `bool` indicating whether a value was returned. This is only useful if the New field is optional: we could also change this to require the New field to be set, or to provide a default implementation that returns the zero value of `T`.~~

```Go
// A Pool is a set of temporary objects of type T that may be individually saved and retrieved.
// ...and so forth
type Pool[T any] struct {
    ...
}

// NewPool returns a new pool. If the newf argument is not nil, then when the pool is empty,
// newf is called to fetch a new value. This is useful when the values in the pool should be initialized.
func NewPool[T any] func(newf func() T) *Pool[T]

// Put adds x to the pool.
func (p *Pool[T]) Put(x T)

// Get selects an arbitrary item from the Pool, removes it from the
// Pool, and returns it to the caller.
// ...and so forth
//
// If Get does not have a value to return, and p was created with a call to [NewPool] with a non-nil argument,
// Get returns the result of calling the function passed to [NewPool].
func (p *Pool[T]) Get() T
```