type Nullable[T any] struct {
T
valid bool
}
Regards.--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/f2b8c317-9530-45ff-b9f2-e9fe209a062cn%40googlegroups.com.
3. Someone comes up with a clever new compromise.
type Nullable[T any] struct {
T
valid bool
}
var y X[*strings.Reader]
F[*strings.Reader]()
type X[T any] struct {T*bufio.Reader}
func F[T any]() {
G[T]()}func G[T any]() {var x X[T]x.Read}
I do recognize that deep call stacks may cause difficulty for this proposal, but my logical reasoning about them (vs. me knowing how it would to be implemented) tells me that `main()` should be able to see the generic type that `F()` requires because `F()` should be able to see the generic type that `G()` requires which is type `X`, and type `X` implements a `Read()` thus making it ambiguous with `*strings.Reader`:
[…]
Unless it is effectively not possible to implement that type of logic in the Go compiler because of design decisions — possibly related to compilation performance — then it seems logical the Go compiler should be able to recognize the conflict and generate a compile error on such combinations at the point of passing the type parameter, explicitly or implicitly.
While not a perfect solution — since it would disallow edge cases where a developer feels they really must create a struct with both type parameters and use with types that create ambiguity — such a compromise would stop perfect from being the enemy of the good.Anyway, as stated this is a strawman proposal. Please shoot holes in it if there are any opportunities to do so.-Mike
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/eaf71dec-e078-48bd-907c-ed7ff1ada222n%40googlegroups.com.
If the signature of a function says you are allowed to call the function, you should be allowed to call the function.
It was a conscious decision during the generics design to *not* do type-checking of generic function bodies during instantiation time, but to be able to compile the body of a generic function and the caller of a generic function separately.
While I'd argue we would be best to stick to objective arguments and not ones that affirm the consequent
, I'll nonetheless revise the proposal that does include all knowledge in the signature, see below.It was a conscious decision during the generics design to *not* do type-checking of generic function bodies during instantiation time, but to be able to compile the body of a generic function and the caller of a generic function separately.Unless I am misunderstanding how the compiler works, I was proposing type-checking during compile-time, not instantiation time.
On to the revised proposal. Assuming your example type again:type X[T any] struct {
T
*bufio.Reader
}Let us agree that it should not compile because of the stated conflicts.Instead, let us assume an extension to type constraints that would allow us to say that "A valid type is `any` type, except for those that implement the methods of type Y." Using `!` as an placeholder sigil for that intent, and adding the sigil `&`, we could have the following type constraint:
type Xable interface {
any & !*bufio.Reader
}(While `!` is probably a bad choice — which is why I said it was a placeholder — it allows me to illustrate the concept in potential code.)
Alternately, maybe using `-` would be better?:type Xable interface {
any -*bufio.Reader
}From the type constraint `Xable` it seems to me we could have the following, which should allow the compiler to do compile-type checking, without having to reach into deeply nested dependencies:
type X[T Xable] struct {
T
*bufio.Reader
}The above should give the OP all reasonable functionality I believe they were requesting and usefully expand the capabilities of generics. That is, unless there are objective arguments for why that can't reasonably be compiled, or there are unintended conflict elsewhere in the language?-Mike
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/67c3cf8d-a6ae-4968-991f-df09e9f86475n%40googlegroups.com.
I took this idea into account in my original message. It is bullet point 2. The case against this is that it would likely make type-checking Go code (co-)NP-complete.If you watch my talk about methods in union elements (or read the supplemental blog post about it), you'll see that I have to spend a bit of work on constructing a negation to prove (co-)NP-completeness.If we just put in a negation operator, that work would no longer even be necessary and the proof becomes trivial. In fact, C++ concepts *have* a plain negation operator in their constraint language and are known to be NP-complete to type-check.
One of the things I have really appreciated about the Go language — and a main reason I was drawn to it — was how the Go team has been pragmatic in the past instead of allowing conceptual purity to block functionality that would be useful in service of software engineering.Specifically to your argument about negation and NP-completeness, yes in the general case unrestrained negation could result in NP-completeness.However, a better and more pragmatic approach would be to restrain negation to those things that can be performed efficiently.
For the case of type embedding, the methods of `Y` are known at compile time and the type methods can be compared as efficiently with the type parameter as checking methods of an interface parameter. That is unless there is some other unintended consequences I am not seeing and you have not mentioned.
-Mike
P.S. Ironically, ensuring the benefits of embedded type parameters are "too small" is itself a class of NP problem.
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/5f4208fe-730b-41cb-bd55-62f7d9bdbb58n%40googlegroups.com.
Hi,I think the reason this has not happened is that it makes code using such a type invalid, depending on the type-argument - in ways not captured by the constraint. For example:type X[T any] struct {T*bufio.Reader}func main() {var x X[int]x.Read // definitely refers to X.Reader.Readvar y X[*strings.Reader]y.Read // ambiguous}Note, in particular, that this might happen very deeply in the call stack, as you can have a generic function instantiating a generic type with a type parameter as well.func main() {F[*strings.Reader]()}func F[T any]() {G[T]()}func G[T any]() {var x X[T]x.Read}For us to actually allow embedding that way, one of three things would need to happen: