golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
121.02k stars 17.36k forks source link

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

Open chochihim opened 1 week ago

chochihim commented 1 week ago

Go Programming Experience

Intermediate

Other Languages Experience

No response

Related Idea

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

ianlancetaylor commented 1 week ago

Why not just use a comment?

thediveo commented 6 days ago

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

chochihim commented 6 days ago

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
ianlancetaylor commented 6 days ago

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.

mainjzb commented 3 days ago

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"
chochihim commented 3 days ago

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?

ianlancetaylor commented 2 days ago

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.