go icon indicating copy to clipboard operation
go copied to clipboard

proposal: Go 2: allow import package name to be put after import path

Open chochihim opened this issue 1 year ago • 7 comments

Go Programming Experience

Intermediate

Other Languages Experience

No response

Related Idea

  • [ ] Has this idea, or one like it, been proposed before?
  • [ ] Does this affect error handling?
  • [ ] Is this about generics?
  • [X] Is this change backward compatible? Breaking the Go 1 compatibility guarantee is a large cost and requires a large benefit

Has this idea, or one like it, been proposed before?

No

Does this affect error handling?

No

Is this about generics?

No

Proposal

Allow import package name to be put after import path, i.e allow the following:

import (
    "time"
    
    "github.com/xxx/yyy/zzz" myxyzutil
)

Language Spec Changes

-ImportSpec       = [ "." | PackageName ] ImportPath .
+ImportSpec       = [ "." | PackageName ] ImportPath | ImportPath [ "." | PackageName ] .

Informal Change

No response

Is this change backward compatible?

Yes

Orthogonality: How does this change interact or overlap with existing features?

No response

Would this change make Go easier or harder to learn, and why?

Consider the following change for example:

import (
	"fmt"
	"net"
	"reflect"
	"strconv"
	"time"

	"k8s.io/api/admissionregistration/v1" admissionregistrationv1
	"k8s.io/api/admissionregistration/v1alpha1" admissionregistrationv1alpha1
	"k8s.io/api/admissionregistration/v1beta1" admissionregistrationv1beta1
	"k8s.io/api/apiserverinternal/v1alpha1" apiserverinternalv1alpha1
	"k8s.io/api/apps/v1" appsv1
	"k8s.io/api/authentication/v1" authenticationv1
	"k8s.io/api/authentication/v1alpha1" authenticationv1alpha1
	"k8s.io/api/authentication/v1beta1" authenticationv1beta1
	"k8s.io/api/authorization/v1" authorizationapiv1
	"k8s.io/api/autoscaling/v1" autoscalingapiv1
	"k8s.io/api/autoscaling/v2" autoscalingapiv2
	"k8s.io/api/batch/v1" batchapiv1
	"k8s.io/api/certificates/v1" certificatesapiv1
	"k8s.io/api/certificates/v1alpha1" certificatesv1alpha1
	"k8s.io/api/coordination/v1" coordinationapiv1
	"k8s.io/api/core/v1" apiv1
	"k8s.io/api/discovery/v1" discoveryv1
	"k8s.io/api/events/v1" eventsv1
	"k8s.io/api/networking/v1" networkingapiv1
	"k8s.io/api/networking/v1alpha1" networkingapiv1alpha1
	"k8s.io/api/node/v1" nodev1
	"k8s.io/api/policy/v1" policyapiv1
	"k8s.io/api/rbac/v1" rbacv1
	"k8s.io/api/resource/v1alpha2" resourcev1alpha2
	"k8s.io/api/scheduling/v1" schedulingapiv1
	"k8s.io/api/storage/v1" storageapiv1
	"k8s.io/api/storage/v1alpha1" storageapiv1alpha1
	"k8s.io/api/storage/v1beta1" storageapiv1beta1
	"k8s.io/api/storagemigration/v1alpha1" svmv1alpha1
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/net" utilnet
	"k8s.io/apiserver/pkg/endpoints/discovery"
	"k8s.io/apiserver/pkg/server" genericapiserver
	"k8s.io/apiserver/pkg/server/storage" serverstorage
	"k8s.io/apiserver/pkg/util/feature" utilfeature
	"k8s.io/client-go/discovery" clientdiscovery
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/kubernetes/typed/core/v1" corev1client
	"k8s.io/client-go/kubernetes/typed/discovery/v1" discoveryclient
	"k8s.io/klog/v2"
	"k8s.io/kubernetes/pkg/apis/core" api
	"k8s.io/kubernetes/pkg/apis/flowcontrol/v1" flowcontrolv1
	"k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta1" flowcontrolv1beta1
	"k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta2" flowcontrolv1beta2
	"k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta3" flowcontrolv1beta3
	"k8s.io/kubernetes/pkg/controlplane/apiserver" controlplaneapiserver
	"k8s.io/kubernetes/pkg/controlplane/apiserver/options"
	"k8s.io/kubernetes/pkg/controlplane/controller/defaultservicecidr"
	"k8s.io/kubernetes/pkg/controlplane/controller/kubernetesservice"
	"k8s.io/kubernetes/pkg/controlplane/reconcilers"
	"k8s.io/kubernetes/pkg/features"
	"k8s.io/kubernetes/pkg/kubeapiserver/options" kubeoptions
	"k8s.io/kubernetes/pkg/kubelet/client" kubeletclient

	// RESTStorage installers
	"k8s.io/kubernetes/pkg/registry/admissionregistration/rest" admissionregistrationrest
	"k8s.io/kubernetes/pkg/registry/apiserverinternal/rest" apiserverinternalrest
	"k8s.io/kubernetes/pkg/registry/apps/rest" appsrest
	"k8s.io/kubernetes/pkg/registry/authentication/rest" authenticationrest
	"k8s.io/kubernetes/pkg/registry/authorization/rest" authorizationrest
	"k8s.io/kubernetes/pkg/registry/autoscaling/rest" autoscalingrest
	"k8s.io/kubernetes/pkg/registry/batch/rest" batchrest
	"k8s.io/kubernetes/pkg/registry/certificates/rest" certificatesrest
	"k8s.io/kubernetes/pkg/registry/coordination/rest" coordinationrest
	"k8s.io/kubernetes/pkg/registry/core/rest" corerest
	"k8s.io/kubernetes/pkg/registry/discovery/rest" discoveryrest
	"k8s.io/kubernetes/pkg/registry/events/rest" eventsrest
	"k8s.io/kubernetes/pkg/registry/flowcontrol/rest" flowcontrolrest
	"k8s.io/kubernetes/pkg/registry/networking/rest" networkingrest
	"k8s.io/kubernetes/pkg/registry/node/rest" noderest
	"k8s.io/kubernetes/pkg/registry/policy/rest" policyrest
	"k8s.io/kubernetes/pkg/registry/rbac/rest" rbacrest
	"k8s.io/kubernetes/pkg/registry/resource/rest" resourcerest
	"k8s.io/kubernetes/pkg/registry/scheduling/rest" schedulingrest
	"k8s.io/kubernetes/pkg/registry/storage/rest" storagerest
	"k8s.io/kubernetes/pkg/registry/storagemigration/rest" svmrest
)

where all the package name aliases are put after the import path. In this way, I can tell more easily at the glance about what kinds of domains/functionalities are imported. In my opinion, this improves the readability.

Cost Description

No response

Changes to Go ToolChain

No response

Performance Costs

No response

Prototype

No response

chochihim avatar Jun 24 '24 08:06 chochihim

Why not just use a comment?

ianlancetaylor avatar Jun 24 '24 13:06 ianlancetaylor

The spec proposal allows foo "example.org/goo/bar" baz, what gives?

thediveo avatar Jun 24 '24 16:06 thediveo

Why not just use a comment?

Comment definitely works. But I think a package's own import path is already a good information about itself.

Also it is a bit about readability and aesthetics. I will use below image to better illustrate my point:

Screenshot 2024-06-25 at 11 29 05 AM

The blue bars are those well-organised import paths and red bars are various-lengthed import names. Putting import names after import path just make the code looks better imho.

On the other hands, I think a package name is just a implementation detail which is in general to be put after declaration/definition. Many other languages also put alias after the importing module name/path. For example:

Kotlin:

import org.test.Message as TestMessage

Python:

import package_name.subpackage_name.module_name as pkg_mod_abbrev

chochihim avatar Jun 25 '24 03:06 chochihim

We already have a way to do import aliases. We are not going to introduce another way to do the same thing. The benefit is not worth the cost of a language change.

ianlancetaylor avatar Jun 25 '24 13:06 ianlancetaylor

If just need improves the readability. add futrue like comment alignment in gofmt that import path alignment

        api                   "k8s.io/kubernetes/pkg/apis/core"
        flowcontrolv1         "k8s.io/kubernetes/pkg/apis/flowcontrol/v1" 
        flowcontrolv1beta1    "k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta1" 
	flowcontrolv1beta2    "k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta2" 
	flowcontrolv1beta3    "k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta3" 
	controlplaneapiserver "k8s.io/kubernetes/pkg/controlplane/apiserver" 
hint   /*options */	      "k8s.io/kubernetes/pkg/controlplane/apiserver/options"

mainjzb avatar Jun 28 '24 07:06 mainjzb

If just need improves the readability. add futrue like comment alignment in gofmt that import path alignment

        api                   "k8s.io/kubernetes/pkg/apis/core"
        flowcontrolv1         "k8s.io/kubernetes/pkg/apis/flowcontrol/v1" 
        flowcontrolv1beta1    "k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta1" 
	flowcontrolv1beta2    "k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta2" 
	flowcontrolv1beta3    "k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta3" 
	controlplaneapiserver "k8s.io/kubernetes/pkg/controlplane/apiserver" 
hint   /*options */	      "k8s.io/kubernetes/pkg/controlplane/apiserver/options"

Given that gofmt already formats struct in a similar way, it looks good enough for me. Just one thing though, how should we format when both with- and without- alias imports are mixed together?

Should it be

import (
	                      "k8s.io/klog/v2"
	api                   "k8s.io/kubernetes/pkg/apis/core"
	flowcontrolv1         "k8s.io/kubernetes/pkg/apis/flowcontrol/v1"
	flowcontrolv1beta1    "k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta1"
	flowcontrolv1beta2    "k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta2"
	flowcontrolv1beta3    "k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta3"
	controlplaneapiserver "k8s.io/kubernetes/pkg/controlplane/apiserver"
	                      "k8s.io/kubernetes/pkg/controlplane/apiserver/options"
	                      "k8s.io/kubernetes/pkg/controlplane/controller/defaultservicecidr"
	                      "k8s.io/kubernetes/pkg/controlplane/controller/kubernetesservice"
	                      "k8s.io/kubernetes/pkg/controlplane/reconcilers"
	                      "k8s.io/kubernetes/pkg/features"
	kubeoptions           "k8s.io/kubernetes/pkg/kubeapiserver/options"
	kubeletclient         "k8s.io/kubernetes/pkg/kubelet/client"
)

or

import (
	"k8s.io/klog/v2"
	api                   "k8s.io/kubernetes/pkg/apis/core"
	flowcontrolv1         "k8s.io/kubernetes/pkg/apis/flowcontrol/v1"
	flowcontrolv1beta1    "k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta1"
	flowcontrolv1beta2    "k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta2"
	flowcontrolv1beta3    "k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta3"
	controlplaneapiserver "k8s.io/kubernetes/pkg/controlplane/apiserver"
	"k8s.io/kubernetes/pkg/controlplane/apiserver/options"
	"k8s.io/kubernetes/pkg/controlplane/controller/defaultservicecidr"
	"k8s.io/kubernetes/pkg/controlplane/controller/kubernetesservice"
	"k8s.io/kubernetes/pkg/controlplane/reconcilers"
	"k8s.io/kubernetes/pkg/features"
	kubeoptions           "k8s.io/kubernetes/pkg/kubeapiserver/options"
	kubeletclient         "k8s.io/kubernetes/pkg/kubelet/client"
)

?

@ianlancetaylor What do you think? Will PR like this be accepted?

chochihim avatar Jun 28 '24 08:06 chochihim

That would have to go through a different proposal. I don't think it's likely to be accepted. Changing gofmt is painful because it causes presubmits to break across all people using Go, especially if they are mixing versions.

ianlancetaylor avatar Jun 28 '24 16:06 ianlancetaylor

We aren't going to introduce a new syntax that exactly replicates the existing syntax in a different way. The emoji voting is not in favor. Therefore, this is a likely decline. Leaving open for four weeks for final comments.

ianlancetaylor avatar Aug 07 '24 21:08 ianlancetaylor

I like this, though. Sorting import lists in this format becomes trivial.

More importantly, the reader does not have to zigzag his eyes between the two ends of each line of the import list to see what was aliased and to what, since all of the import aliases sit snugly next to all the original and unaliased package names at the rightmost ends of the lines.

antichris avatar Aug 09 '24 18:08 antichris

Unfortunately, this is not a change that we can make. No change in consensus, so declined. — rfindley for the language proposal review group

findleyr avatar Sep 04 '24 21:09 findleyr