What worries me is code like this:
func f() any {
int *i
return i
}
func main() {
if f()==nil {
...
}
}
Use of "any" makes it look like f returns an *int and f() is nil, but
it is not, because "any" is interface{}.
I think "any" as a constraint is useful, like "comparable", but "any"
as a type is misleading.
Isn't your example just a case of confusing a nil interface with a nil value inside a generic interface? How does requiring writing it as `func f() interface{} {` make the behavior any clearer?
--
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/10264F88-82EB-4E01-AF28-E2057C08571E%40iitbombay.org.
interface{}, when used as a constraint, doesn't mean than the value
has to be an interface{}, it means the value can be anything.
interface{}, when used as a value, doesn't mean that the value can be
anything, it means that the value is an interface, and you have to get
the value from that interface. Different uses, different identifiers.
Just to clarify, the intent is to make the declaration in the spec `type any = interface{}`, not `type any interface{}`, correct? The latter would be more analogous to `error`. Either has certain advantages and disadvantages, I'm not sure which I prefer, but I just want to make sure I understand the plan :)
2.
We’re going to simplify the rule for type list satisfaction. The type
argument will satisfy the constraint if the type argument is identical
to any type in the type list, or if the underlying type of the type
argument is identical to any type in the type list. What we are
removing here is any use of the underlying types of the types in the
type list. This tweaked rule means that the type list can decide
whether to accept an exact defined type, other than a predeclared
type, or whether to accept any type with a matching underlying type.
This is a subtle change that we don’t expect to affect any existing
experimental code.
We think that this definition might work if we permit interface types
with type lists to be used outside of type constraints. Such
interfaces would effectively act like sum types. That is not part of
this design draft, but it’s an obvious thing to consider for the
future.
Note that a type list can mention type parameters (that is, other type
parameters in the same type parameter list). These will be checked by
first replacing the type parameter(s) with the corresponding type
argument(s), and then using the rule described above.
3.
We’re going to clarify that when considering the operations permitted
for a value whose type is a type parameter, we will ignore the methods
of any types in the type list. The general rule is that the generic
function can use any operation permitted by every type in the type
list. However, this will only apply to operators and predeclared
functions (such as "len" and "cap"). It won’t apply to methods, for
the case where the type list includes a list of types that all define
some method. Any methods must be listed separately in the interface
type, not inherited from the type list.
This rule seems generally clear, and avoids some complex reasoning
involving type lists that include structs with embedded type
parameters.
4.
We’re going to permit type switches on type parameters that have type
lists, without the “.(type)” syntax. The “(.type)” syntax exists to
clarify code like “switch v := x.(type)”. A type switch on a type
parameter won’t be able to use the “:=” syntax anyhow, so there is no
reason to require “.(type)”. In a type switch on a type parameter
with a type list, every case listed must be a type that appears in the
type list (“default” is also permitted, of course). A case will be
chosen if it is the type matched by the type argument, although as
discussed above it may not be the exact type argument: it may be the
underlying type of the type argument. To make that rule very clear,
type switches will not be permitted for type parameters that do not
have type lists. It is already possible to switch on a value “x”
whose type is a type parameter without a type list by writing code
like “switch (interface{})(x).(type)” (which may now be written as
“switch any(x).(type)”). That construct is not the simplest, but it
uses only features already present in the language, and we don’t
expect it to be widely needed.
All constraints except "any" specify a constraint for the type. A
Stringer constraint will ensure that the type has String() string
method. "any" is a lack of constraint.
My problem is the attractiveness of "any" as a return type.
Ian
--
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/CAOyqgcUFU_Lz0c%3D-6V6N9X2Ku2Hx-9%2BDeHequ0oLX9Soyo_3GQ%40mail.gmail.com.
People don't use the empty interface because they like it so much, but because Go doesn't have parametric polymorphism / "generics" yet.
My one concern with making it an alias is error messages.If the source code says "any", I think so should the error messages. Currently, the compiler forgets aliases too early.
My one concern with making it an alias is error messages.If the source code says "any", I think so should the error messages. Currently, the compiler forgets aliases too early.
We’re going to simplify the rule for type list satisfaction. The type
I'd assume that would fail to compile as you're returning a []T not a []int
On Fri, 21 Aug 2020 at 22:10, jimmy frasche <soapbo...@gmail.com> wrote:I'd assume that would fail to compile as you're returning a []T not a []intIf that's the case, then I'm not sure that such a type switch would be very useful. It would tell you what type the values are, but you can't do anything with them because all the values would still be of the original type.
I had assumed that the intention was that within the arm of the type switch, the switched type would take on the specified type.That would allow (for example) specialising to use underlying machine operations on []T when T is a known type such as byte.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAJhgacjTm%3DC-6f%2B4%2BA0HCTDT0_U7pQZOmRjShuzigdocDzAcww%40mail.gmail.com.
Yes, there are various such possibilities.
What jimmy frasche said above is correct: nothing changes in the case
of a type switch of a type parameter. The code now knows the type
list element that the type argument matched, but it can't do anything
that it couldn't do anyhow.
Yes, there are various such possibilities.
What jimmy frasche said above is correct: nothing changes in the case
of a type switch of a type parameter. The code now knows the type
list element that the type argument matched, but it can't do anything
that it couldn't do anyhow.
On Fri, Aug 21, 2020 at 11:46 PM Ian Lance Taylor <ia...@golang.org> wrote:Yes, there are various such possibilities.
What jimmy frasche said above is correct: nothing changes in the case
of a type switch of a type parameter. The code now knows the type
list element that the type argument matched, but it can't do anything
that it couldn't do anyhow.I think there are two reasonable things that it could be allowed to do in the case, that aren't allowed outside:1. Convert to the matched type. We have a guarantee that the matched type is either identical or has the same underlying type, both of which would allow a conversion in the language as-is. I feel allowing this conversion would be sufficiently useful (e.g. passing things to `strconv.Itoa` or functions from `math` can be very useful).
2. If the type is not a predeclared type, we could even take this a step further, as the types must be identical - so we might allow treating them as such.
This feels natural when viewed from the "type lists are essentially sum types" POV. However, it would treat predeclared types more special than other declared types and so it may be too elaborate to put into the spec. It would also allow what rog suggest - but only in certain corner cases, which feels weird.The more I think about it, the less I understand the intention behind the type-switch construct introduced. I tend to agree that 1. at least should be possible to make it useful. But even then, it seems like kind of a big change for relatively limited use. What was the motivation behind that change? Is there discussion somewhere, of interesting use-cases this enables?
I don't want a generic min unless it looks like this:
func Min[T constraints.Ordered](a, b T) T {
switch T {
case float32:
return T(math.Min(float32(a), float32(b)))
case float64:
return T(math.Min(float64(a), float64(b)))
}
if a < b {
return a
}
return b
}
[...]
> I don't see why anybody would find it attractive as a return type. People don't use the empty interface because they like it so much, but because Go doesn't have parametric polymorphism / "generics" yet. There are many programming languages that have a named top type and it is rarely abused. Programmers want to write type safe code if they can.
I disagree. Especially people coming from other languages with a
strong emphasis on DRY tend to overuse interface{}, many times
incorrectly, and generics will not fix that. "any" will make it more
attractive, because it no longer looks like an interface. I agree that
this is a hypothetical problem at this point without any actual
complaints from developers. But defining an alias "any" is easy if you
need it. Providing one predefined is endorsing its use.
On Fri, 21 Aug 2020 at 23:12, jimmy frasche <soapbo...@gmail.com> wrote:I don't want a generic min unless it looks like this:
func Min[T constraints.Ordered](a, b T) T {
switch T {
case float32:
return T(math.Min(float32(a), float32(b)))
case float64:
return T(math.Min(float64(a), float64(b)))
}
if a < b {
return a
}
return b
}I'd really like to be able to write that as:func Min[T constraints.Ordered](a, b T) T {
switch T {
case float32:return math.Min(float64(a), float64(b))
case float64:
return math.Min(a, b)
}
if a < b {
return a
}
return b}
I probably didn't read what you have wrote in the first message carefuly enough. Does it mean something like that will worktype SomeTypes interface {type int, float32, float64}func Min[T SomeTypes](x, y T) T {switch T {case int:if x < y {return x}return ycase float32:return math.Min(float64(x), float64(y))case float64:return math.Min(x, y)}}
Would something like below work as well?type Compare[T any] interface {Compare(x, y T) int}type CompareConstraints[T any] {type int, int8, …, float64, string, Compare[T]}func Min[T CompareConstraints]Min(x, y T) bool {switch T {case int:…
…case Compare[T]:return x.Compare(y) < 0}}
Applying the same rule to type lists and type switches you should be able to writetype Comparer[T any] interface {Compare(T) int}type CompareConstraints interface {type int, int8, …, float64, string, Comparer}func Min[T CompareConstraints](x, y T) bool {switch T {case int:…
…case Comparer:if x.Compare(y) < 0 {return x}return y}}But the current proposal does not allow interfaces in type lists.
--
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/03342d1f-5c82-40e6-98fc-18e95bfd183cn%40googlegroups.com.
We’re going to settle on square brackets for the generics syntax.
I've seen objections that a language change for generics should not
implicitly pull in a change to non-generic code. That seems fair. It
may be the right thing to do, but it should be justified separately.
So we're going to start with "any" only being accepted as a type
constraint, and we can discuss making the name available for all uses
separately, probably on issue 33232.
> possibility of using angle bracketsPlease stop
- call these operator signs “brackets”
- pretending they are good in a role of brackets — they are not
- spreading this nonsense from C syntax family of languages to saner once — yes, you heard it right. C is known for its chaotic development and lack of careful planning.
- thinking yet another strange workaround is a good thing
After many discussions and reading many comments, we plan to move
forward with some changes and clarifications to the generics design
draft.
1.
We’re going to settle on square brackets for the generics syntax.
We’re going to permit type switches on type parameters that have type
lists, without the “.(type)” syntax. The “(.type)” syntax exists to
clarify code like “switch v := x.(type)”. A type switch on a type
parameter won’t be able to use the “:=” syntax anyhow, so there is no
reason to require “.(type)”. In a type switch on a type parameter
with a type list, every case listed must be a type that appears in the
type list (“default” is also permitted, of course). A case will be
chosen if it is the type matched by the type argument, although as
discussed above it may not be the exact type argument: it may be the
underlying type of the type argument. To make that rule very clear,
type switches will not be permitted for type parameters that do not
have type lists. It is already possible to switch on a value “x”
whose type is a type parameter without a type list by writing code
like “switch (interface{})(x).(type)” (which may now be written as
“switch any(x).(type)”). That construct is not the simplest, but it
uses only features already present in the language, and we don’t
expect it to be widely needed.
These changes will soon be implemented in the experimental design on
the dev.generics branch, and in the go2go playground. Some of them
already work. We will update the design draft accordingly.
We welcome any comments. Thanks for all the help that so many people
have provided so far.
Ian & Robert
If it is intended at simplification for parsers, […] If it is intended to improve readability for readers of generic code
I think that the opposite is happening. Writing `any/interface{}` for a non-constrained type adds more clutter than it contributes to reading uniformity. It is common in languages such as TypeScript and Java for a non-constrained type to be simply written as "T", which in my experience, has been readable and clutter-free.
On Monday, August 31, 2020 at 11:04:17 PM UTC+5:30 Ian Lance Taylor wrote:On Mon, Aug 31, 2020 at 10:25 AM samir.el...@gmail.com
<samir.el...@gmail.com> wrote:
>
> Great improvements. Well done.
>
> Any intentions to make methods accept additional type arguments ?
See https://go.googlesource.com/proposal/+/refs/heads/master/design/go2draft-type-parameters.md#No-parameterized-methods
.
Ian
--
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/269b0470-d197-4a7d-af37-bec63e27ef10n%40googlegroups.com.
After many discussions and reading many comments, we plan to move
forward with some changes and clarifications to the generics design
draft.
1.
We’re going to settle on square brackets for the generics syntax.
We’re going to drop the “type” keyword before type parameters, as
using square brackets is sufficient to distinguish the type parameter
list from the ordinary parameter list. To avoid the ambiguity with
array declarations, we will require that all type parameters provide a
constraint. This has the advantage of giving type parameter lists the
exact same syntax as ordinary parameter lists (other than using square
brackets). To simplify the common case of a type parameter that has
no constraints, we will introduce a new predeclared identifier “any”
as an alias for “interface{}”.
The result is declarations that look like this:
type Vector[T any] []T
func Print[T any](s []T) { … }
func Index[T comparable](s []T, e T) { … }
We feel that the cost of the new predeclared identifier “any” is
outweighed by the simplification achieved by making all parameter