From d167a56873482936a8b4822dac7192f237acabff Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 11 Aug 2025 13:29:34 +0200 Subject: [PATCH] nat: make PortMap and PortSet aliases The `PortSet` and `PortMap` types don't carry a real meaning on their own. Their purpose is defined at locations where they're used, such as `Container.ExposedPorts` or `Container.PortBindings`. Their documentation also shows this; // PortSet is a collection of structs indexed by [PortRangeProto]. // PortMap is a collection of [PortBinding] indexed by [PortRangeProto]. Which, almost literally, describes what a map is. Substituting the types for their implementation doesn't lose any meaning; // map[PortRangeProto]struct{} is a collection of structs indexed by [PortRangeProto]. // map[PortRangeProto][]PortBinding is a collection of [PortBinding] indexed by [PortRangeProto]. Neither type has any special handling connected to them (no methods or otherwise), so they are just maps with a fancy name attached. Worse, using the extra indirect induces cognitive load; it's not clear from the type that it's "just" a map, indexed by `PortBinding`, and it's not clear what (kind of) values are in the map. There are cases where having a type defined can add value to provide a more in-depth description of their intent, but (as shown above) even that is not the case here. I'm considering these types to be premature abstraction with no good value. As they are a "straight" copy of a map with the same signature, replacing these types preserves backward compatibility; existing code can assign either a `PortSet` or `PortMap`, or a `map[PortRangeProto]..` with the same signature, but we can deprecate the types to give users a nudge to use a regular map instead. The following shows that they are interchangeable; type config1 struct { ExposedPorts container.PortSet PortBindings container.PortMap } type config2 struct { ExposedPorts map[container.PortRangeProto]struct{} PortBindings map[container.PortRangeProto][]container.PortBinding } var ( ports map[container.PortRangeProto]struct{} portBindings map[container.PortRangeProto][]container.PortBinding ports2 container.PortSet portBindings2 container.PortMap ) _ = config1{ ExposedPorts: ports, PortBindings: portBindings, } _ = config1{ ExposedPorts: ports2, PortBindings: portBindings2, } _ = config2{ ExposedPorts: ports, PortBindings: portBindings, } _ = config2{ ExposedPorts: ports2, PortBindings: portBindings2, } Signed-off-by: Sebastiaan van Stijn --- nat/nat.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nat/nat.go b/nat/nat.go index 9a366fbf..3db9d188 100644 --- a/nat/nat.go +++ b/nat/nat.go @@ -18,10 +18,10 @@ type PortBinding struct { } // PortMap is a collection of PortBinding indexed by Port -type PortMap map[Port][]PortBinding +type PortMap = map[Port][]PortBinding // PortSet is a collection of structs indexed by Port -type PortSet map[Port]struct{} +type PortSet = map[Port]struct{} // Port is a string containing port number and protocol in the format "80/tcp" type Port string