I am proposing the concept of a "not import" which can reduce dependencies and file sizes, and perhaps assist with dead code elimination.
The concept is better elucidated by explaining my use case (and showing that using interfaces is inadequate):
dbq github.com/rocketlaunchr/dbq/v2.database/sql but is designed to work with mysql driver and postresql driver only.database/sql to compare it with mysql specific errors and postgres specific errors to perform specific behaviours:Hypothetical example:
import (
~ "github.com/lib/pq"
~ "github.com/go-sql-driver/mysql"
)
_, err := db.QueryRow("query", id).Scan(&nt)
switch v := err.(type) {
case nil:
return nil
case *mysql.MySQLError:
return v.Number
case *pq.Error:
return v.Code
default:
}
In the type switch above, if the consumer project (or any other dependency of the consumer project) does not import mysql or pq, then the compiler will just ignore that case.
For comma, ok form type assertions, ok will return false
For standard type assertions, if the consumer project (or any other dependency of the consumer project) imports the mysql or pq package, it will work as per normal. Otherwise the compiler exits with an error.
Any func init() inside a "not import" will not run unless the consumer project (or any other dependency of the consumer project) imports it.
If there are any exported functions with arguments or return values that rely on the import, then compiler exits with an error => programmer must change it from a "not import"
For non-exported functions, the compiler will eliminate the function (dead code elimination) based on code path.
I haven't had time to think it through comprehensively. I already anticipate some issues. At this stage, please interpret my proposal with regards to the spirit and objective of what I'm trying to achieve and provide feedback and insight below so that I can refine it.
why not provide subpackages: one for mysql and one for pgsql?
My initial reaction is that dash and underscore imports would be very similar, and likely to be misread/confused:
import (
- "foo"
_ "bar"
- "baz"
)
It's also not immediately obvious what - means. _ already has a broad meaning of "ignore the following" in Go, and with dot-imports, . follows how the dot is part of qualified names from imported packages.
Dash means negative which means "don't include". The specific syntax is not important. It could be anything including a # or : or ~
import (
- "foo"
_ "bar"
~ "baz"
# "baz"
: "baz"
)
For this specific case, couldn't you use reflection to access the relevant data without a hard dependency on those error types?
_, err := db.QueryRow("query", id).Scan(&nt)
if err == nil {
return 0
}
switch verr := reflect.Indirect(reflect.ValueOf(err)); {
case verr.PkgPath() == "github.com/go-sql-driver/mysql" && verr.Name() == "MySQLError":
return v.FieldByName("Number").Interface()
case verr.PkgPath() == "github.com/lib/pq" && verr.Name() == "Error":
return v.FieldByName("Code").Interface()
}
This is related to #38450, which addresses dead code elimination in a different way. If all of a package's code is eliminated, then the remaining type assertions for code like this don't seem like much to worry about.
@dsnet Don't necessarily interpret this proposal are related to my use case. Think of it in terms of a benefit to Go and the Go ecosystem. I've been thinking about this problem even before I encountered my specific use case.
Finally, your approach loses static type checking and not pretty.
Don't necessarily interpret this proposal are related to my use case.
It's hard to realistically evaluate a proposal that is divorced from the concrete use cases that the feature would be useful for.
Finally, your approach loses static type checking
True, but Go reflection is a approach that works today without the addition of an entire language feature with many subtleties involved.
reflection also allows the consumer to "trick" the package with a different package but with the same package path name.
@ianlancetaylor I believe #38450 is about indicating that a certain package should not call its init function.
This proposal is about indicating to the compiler/linker that a certain dependency need not be bundled in the executable.
The emphasis is different.
I agree that the emphasis is different, but the result may be similar. When addressing a problem, a tooling change is normally preferable to a language change.
Based on the discussion above, this is a likely decline. Leaving open for four weeks for final comments.
No further comments.
Most helpful comment
My initial reaction is that dash and underscore imports would be very similar, and likely to be misread/confused:
It's also not immediately obvious what
-means._already has a broad meaning of "ignore the following" in Go, and with dot-imports,.follows how the dot is part of qualified names from imported packages.