-
Notifications
You must be signed in to change notification settings - Fork 17.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
proposal: spec: add builtin func 'is[T any](any) bool' #65846
Comments
A more general builtin, and one that could not be written in the language today, would take anything with a 1- or 2-value form and return the second value. For lack of a better name I'll call it |
That is more general, but less clear:
So it doesn't seem to me to be the right axis for generalization. |
I have written plenty of code that wants to know if a value is in a map that must distinguish between zero and absent. Far more often than it was okay to rely on zero and absent being the same. I've wanted Agreed that |
I would like it to be possible to expand the optional-second-value expressions in certain circumstances. For example, func Example[T any](v T) T { return v }
func Example2[T any](v T, ok bool) bool { return ok }
Example(m[k]) // Currently legal.
Example2(m[k]) // Not currently legal. With that available, it would be extremely easy to just write a |
We're losing sight of the point. It's already possible to write an Evidence: grep for |
However, this grep alone does not indicate whether these occurrences would noticeably benefit from being usable in an expression. The difference between using |
But the main question is whether the new builtin improves the readability of the code more than the cost of adding a new builtin into the language. is[T] would help the readability for x/tools but YMMV. |
A thing I frequently see, especially with people first coming to Go from dynamically typed languages, is overuse of And personally, I don't find that there are many cases calling for |
As suggested in an earlier comment, I did a (very unscientific) survey of the codebase I spend my dayjob maintaining, for examples that might benefit from this proposal. This codebase seems to have a pretty even split between During this survey I found three main situations.
This survey contradicted my initial (incorrect) hunch that there wouldn't be many examples of testing the type without then using the value. I expect we'd have plenty of opportunities to use However, I feel ambivalent because of the highly subjective concern I mentioned above: that the very short identifier I expect this concern would reduce if I were exposed to more examples of this in real code, but I'd worry about folks who are new to Go -- who might not have yet learned to read Perhaps choosing a longer name would allow being more specific about what exactly this function means and thus better prime someone to guess what the following characters mean. I don't want to bikeshed about it though; I'm curious to see if others share this concern or if it's just me. Given all of the above, I'm cautiously in favor. |
It occurs to me that predeclared builtins are allowed more flexibility in their signatures, including taking types directly as arguments within the parentheses as we see with e.g. Therefore this proposal could presumably be spelled That of course does come at the expense of orthogonality, and at the expense of a potential opportunity to introduce a newcomer to the syntax for qualifying a generic function when type inference isn't possible. |
I'd like to note that this may conflict with the package https://github.com/matryer/is |
That shouldn't be a problem any more than adding |
it looks like over half of those deal with errors, which could be |
@adonovan, if this was a function in the standard library instead of a builtin, would you view that as acceptable, and any brief thoughts on how you would spell it if so? (Sorry if you already mentioned this).
A quick side note is I think @Merovius has observed that if |
No, generics were considered at that time and deemed less ergonomic: #29934 (comment) |
Now, none builtin functions use the custom generic syntax. So maybe it is not a bad idea to support this function in std instead in my opinion. BTW, @rsc's reply on the generic form of |
Update: Thanks for all the comments. I fixed a couple bugs in the analyzer (https://go.dev/cl/570315) and re-ran it, and updated the list, now partitioned into error and non-error-related cases (roughly 50% each). I agree that a generic errors.As would have been nice, but perhaps that ship has sailed.
No package springs to mind; it's essentially an operator in the language. The closest analogue is min and max, but they obviously belong in the "math" package; there's no obvious counterpart here. |
Change https://go.dev/cl/570315 mentions this issue: |
I am curious how those numbers compare to |
This feels like a kind of disingenuous answer. "Less frustrating breaking out of expression mode" is not a learnability benefit, it's a convenience. I think this is a pretty clear net negative (albeit not a huge one) when it comes to learnability. Personally, I feel rather strongly that this proposal represents an inflationary attitude towards predeclared functions. For most of Go's life, we had a very limited number of predeclared identifiers and that was always advertised as a big benefit. And we only used predeclared functions for things that we could not implement in the language. That changed with Not to go all old-man-yelling-at-cloud, but I don't like it. I disliked adding |
For me it is more the problem that there are already several different kinds of The min and max are somewhat different as they were likely used only for minimum and maximum. For this proposal something like |
If
|
Adding to the ordinary proposal minutes, but I don't think this holds its weight. The vast majority of the time you care about the underlying type of something, you care because you want to use it. The x, ok := v.(T) form gives you the value to use. I can see how having is would be useful in complex conditionals, inside which you would re-type-assert to get the value. That may come up often in the kinds of AST code you write, but for me it almost never comes up. It's necessarily a feature of localized value. To me at least, this doesn't seem worthwhile enough. The language already provides two forms - type assertions and type switches - so the bar for adding a third equivalent form seems quite high to me, and I don't think we have evidence here of meeting that bar. |
This proposal has been added to the active column of the proposals project |
func is (t any, aType ... any) (any,bool) { |
Based on the discussion above, this proposal seems like a likely decline. |
No change in consensus, so declined. |
Go Programming Experience
Experienced
Other Languages Experience
many
Related Idea
Has this idea, or one like it, been proposed before?
Not to my knowledge.
Does this affect error handling?
No.
Is this about generics?
Indirectly.
Proposal
I propose that we add an intrinsic
is
function, equivalent to this Go declaration:This operator makes it possible to test the type of an interface without breaking out of expression mode, which is especially helpful when writing code that makes heavy use of sum types, such as syntax trees, types, XML documents, and so on.
Of course, one can write this function in Go or import it from a package, but like
min
andmax
it is ubiquitous and fundamental, and warrants a short name.Language Spec Changes
The universe scope defines an
is
function, whose declaration is equivalent to the Go code shown above.Informal Change
The
is
operator performs a test of an interface's dynamic type.Is this change backward compatible?
Yes.
Orthogonality: How does this change interact or overlap with existing features?
Very orthogonal.
Would this change make Go easier or harder to learn, and why?
No net change. Harder, because one more thing to learn; easier, because less frustrating breaking out of expression mode.
Cost Description
No response
Changes to Go ToolChain
local changes to cmd/compile, go/types, a few others
Performance Costs
none
Prototype
See above.
The text was updated successfully, but these errors were encountered: