Re: [go-nuts] [ generics ] Added constraint type inference to the design draft

2020-09-09 Thread Steven Blenkinsop
On Tue, Sep 8, 2020 at 9:25 PM Ian Lance Taylor  wrote:

>
> I think that it's really crucial for type inference rules to be as simple
> and clear as possible.  There must never be any confusion as to what an
> inferred type might be.  In complicated cases, it's fine to explicitly list
> the type arguments.  In fact, it's more than fine: it's desirable.
>

This doesn't seem to be a complicated case. We just have a type parameter
that needs pointer methods in order to be passed to another function. I
wouldn't suggest making the inference rules more clever to compensate for
this case. As I mentioned, the compiler probably shouldn't be smart enough
to figure this out as written.

I think the difficulty is coming from conflicting requirements. For element
type inference, you want the freedom to be able to provide arbitrary named
composite types as arguments and get the element type based on structural
matching. But for derived type constraints, you really actually don't want
that extra degree of freedom in the identity of the composite type.
Instead, you want to constrain the specific derived type. Maybe it would be
better to allow derived types to be constrained directly:

https://go2goplay.golang.org/p/cLVkk4HGWre

type Constraint interface{
Method()
}

func Foo[T any, *T Constraint](_ T) {}

func Bar[T any, *T Constraint](t T) {
Foo(t)
}

It might seem weird to have a "parameter" which has to be a specific type
in relation to other parameters, but that's already what was happening with
constraint type inference. This is sort of similar to the original idea of
having pointer type constraints, except you need both T and *T as
parameters, with each being constrained separately.

This doesn't cover the use case of accepting named slice types and
inferring the element type, so constraint type inference would still be
needed. Of course, part of what makes constraint type inference appealing
is that it gets two birds with one stone, but it seems like the conflicting
requirements of the two use cases is undermining the value of both.

On Tue, Sep 8, 2020 at 9:25 PM Ian Lance Taylor  wrote:

> On Tue, Sep 8, 2020 at 5:47 PM Steven Blenkinsop 
> wrote:
>
> >
>
> > Reading over the pointer method example, I noticed that a derived type
> cannot be inferred in a nested call while leaving method constraints intact:
>
> >
>
> > type DerivedTypeConstraint[T any] interface {
>
> > type *T
>
> > Method()
>
> > }
>
> >
>
> > func Foo[T any, PT DerivedTypeConstraint[T]](_ T) {}
>
> >
>
> > func Bar[T any, PT DerivedTypeConstraint[T]](t T) {
>
> > Foo(t) // Error: *T has no methods
>
> > }
>
> >
>
> > type S struct{}
>
> >
>
> > func (S) Method() {}
>
> >
>
> > func main() {
>
> > Bar(S{}) // This is fine, PT gets inferred as *S, which implements Method
>
> > }
>
> >
>
> >
>
> > https://go2goplay.golang.org/p/9GMdhTbcMDs
>
> >
>
> > Obviously, you can work around this by passing PT explicitly rather than
> letting *T be inferred. It's just unfortunate that, even though *T must
> have any methods in the constraint on PT (any other type with the same
> underlying type would have no methods), the compiler isn't, and most likely
> shouldn't be, smart enough to figure that out. I'm not sure how to solve
> this, but I think it makes the design feel a little less polished.
>
>
>
> I think that it's really crucial for type inference rules to be as
>
> simple and clear as possible.  There must never be any confusion as to
>
> what an inferred type might be.  In complicated cases, it's fine to
>
> explicitly list the type arguments.  In fact, it's more than fine:
>
> it's desirable.
>
>
>
> 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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CANjmGJuAZv7AJ-mrBAmOENYj%3Dtn0NmmMtDPmY%2B_BeOuZEO1ACQ%40mail.gmail.com.


Re: [go-nuts] [ generics ] Added constraint type inference to the design draft

2020-09-08 Thread Steven Blenkinsop
Reading over the pointer method example, I noticed that a derived type
cannot be inferred in a nested call while leaving method constraints intact:

type DerivedTypeConstraint[T any] interface {
type *T
Method()
}

func Foo[T any, PT DerivedTypeConstraint[T]](_ T) {}

func Bar[T any, PT DerivedTypeConstraint[T]](t T) {
Foo(t) // Error: *T has no methods
}

type S struct{}

func (S) Method() {}

func main() {
Bar(S{}) // This is fine, PT gets inferred as *S, which implements Method
}


https://go2goplay.golang.org/p/9GMdhTbcMDs

Obviously, you can work around this by passing PT explicitly rather than
letting *T be inferred. It's just unfortunate that, even though *T *must* have
any methods in the constraint on PT (any other type with the same
underlying type would have no methods), the compiler isn't, and most likely
shouldn't be, smart enough to figure that out. I'm not sure how to solve
this, but I think it makes the design feel a little less polished.

On Fri, Aug 14, 2020 at 5:40 AM roger peppe  wrote:

>
>
> On Thu, 13 Aug 2020 at 23:30, Ian Lance Taylor  wrote:
>
>> On Thu, Aug 13, 2020 at 3:09 PM roger peppe  wrote:
>>
>>
>> >
>>
>>
>> > I do feel that the "all or nothing" nature of type parameter lists (if
>> you specify one type parameter, you must explicitly specify all of the
>> others too, even if they could otherwise be inferred) is likely to get in
>> the way here. I'd like to see a way to specify some type parameters and not
>> others, so that constraint type inference can work even when, for example,
>> there's a generic return type parameter that can't be inferred from the
>> arguments. We could potentially use an underscore for that.
>>
>>
>>
>>
>>
>> If I understand you correctly, we changed that when we added the
>>
>>
>> constraint type inference section.  See the updated
>>
>>
>>
>> https://go.googlesource.com/proposal/+/refs/heads/master/design/go2draft-type-parameters.md#type-inference
>>
>>
>> section.
>>
>
> Ah, that's useful and interesting, thanks. I suspect that being able to
> selectively omit type parameters could be useful though - for when there's
> no obvious ordering to the parameters and you want to infer some of the
> earlier types in the list while specifying some later ones. Maybe in
> practice it'll always be possible to use an explicit type conversion in a
> value parameter to do this though, especially if Steven
> Blenkinsop's ordering suggestions are followed (perhaps that could be a `go
> vet` checki).
>
>   cheers,
> rog.
>
>>
>>
>> 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+unsubscr...@googlegroups.com.
>
>
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/golang-nuts/CAJhgacjPfoUp%2Bkhb4csuF%2Bz%3DTEWchZuSri94yTP4%2BtRvtnK5Ng%40mail.gmail.com
> 
> .
>
>
>

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CANjmGJvgk%2BRgAgUwfgDutCGNiqZHzH0KCCh2aZ0Gp_UeG%2BHnjA%40mail.gmail.com.


Re: [go-nuts] [ generics ] Added constraint type inference to the design draft

2020-08-13 Thread Steven Blenkinsop
On Thu, Aug 13, 2020 at 7:35 PM, jimmy frasche 
wrote:

> If I have
>   func F[type E interface{}, S constraints.Slice[E]]() S
> are the following equivalent:
>   F[int, []int]
>   F[int]
>   F[[]int]
> or are only 2 of the 3 permissible? Does that change if I swap the
> type parameters?


>From the section Ian linked:

"When only some type arguments are passed, they are the arguments for the
first type parameters in the list."


On Thu, Aug 13, 2020 at 7:35 PM, jimmy frasche 
wrote:

> If I have
>   func F[type E interface{}, S constraints.Slice[E]]() S
> are the following equivalent:
>   F[int, []int]
>   F[int]
>   F[[]int]
> or are only 2 of the 3 permissible? Does that change if I swap the
> type parameters?
>
> On Thu, Aug 13, 2020 at 4:31 PM Michael Jones 
> wrote:
> >
> > Yes, thank you. In intellectual shame I must say that I somehow
> understood that the generics needed to be "leaf" functions. Thank you for
> demonstrating my oversight. Happier now.
> >
> > Michael
> >
> > On Thu, Aug 13, 2020 at 3:47 PM Bakul Shah  wrote:
> >>
> >> On Aug 13, 2020, at 3:29 PM, Michael Jones 
> wrote:
> >> >
> >> > The all-or-none aspect would be sidestepped if it were allowed to
> define "partial generics":
> >> >
> >> > func A (T1, T2) (...){}
> >> >
> >> > func B(T)(...){ A(T,int)(...){...} }
> >> >
> >> > Allowing B to exist just means running the whole generic thing
> iteratively until no resolution is changed. If the fixed point still has
> generic types then the compilation is a failure, otherwise, a success.
> >>
> >> Do you mean something like this?
> https://go2goplay.golang.org/p/4I4y-dLC-Yp
> >>
> >> >
> >> > Seems useful to me. A generic balanced tree infrastructure could be
> "meta-instantiated" as a LLRB instance that still allows generic leaf types.
> >>
> >
> >
> > --
> > Michael T. Jones
> > michael.jo...@gmail.com
> >
> > --
> > 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+unsubscr...@googlegroups.com.
> > To view this discussion on the web visit
> https://groups.google.com/d/msgid/golang-nuts/CALoEmQxTgQdhS2x4MU%3D_FcwBAJ09D68XnNYOQxy5YV7%2B6QOi0w%40mail.gmail.com
> .
>
> --
> 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+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/golang-nuts/CANG3jXJ60zyaBsYmvOSJdgX3J%3DaB0_Taz2SnuM31Rg3N0bx8mw%40mail.gmail.com
> .
>

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CANjmGJvdPHOC5Uw6DvSeZKXALNuQru_Uaod-cS05a7EAsG7XEw%40mail.gmail.com.


Re: [go-nuts] [ generics ] Added constraint type inference to the design draft

2020-08-13 Thread Steven Blenkinsop
On Thu, Aug 13, 2020 at 6:30 PM Ian Lance Taylor  wrote:

>
> If I understand you correctly, we changed that when we added the
> constraint type inference section.  See the updated
>
> https://go.googlesource.com/proposal/+/refs/heads/master/design/go2draft-type-parameters.md#type-inference
> section.


This change creates two types of type parameters: free type parameters and
*associated* type parameters. And it seems like type parameter lists should
always be specified in the following order:

   1. Free type parameters which *cannot* be inferred based on value
   arguments to the function, followed by
   2. Free type parameters which *can* be inferred based on value arguments
   to the function, followed by
   3. Associated type parameters.

Would this be something that would just be part of style guides, or could
it be enforced in some way (perhaps by a lint)?

Also, is there any suggested way for APIs to document where the "stops" are
between these three categories of type parameters? Currently, the only
possible delimiter is ',', which means type parameter lists currently have
to appear uniform unless you use inline comments.

On Thu, Aug 13, 2020 at 6:30 PM Ian Lance Taylor  wrote:

> On Thu, Aug 13, 2020 at 3:09 PM roger peppe  wrote:
> >
> > I do feel that the "all or nothing" nature of type parameter lists (if
> you specify one type parameter, you must explicitly specify all of the
> others too, even if they could otherwise be inferred) is likely to get in
> the way here. I'd like to see a way to specify some type parameters and not
> others, so that constraint type inference can work even when, for example,
> there's a generic return type parameter that can't be inferred from the
> arguments. We could potentially use an underscore for that.
>
> If I understand you correctly, we changed that when we added the
> constraint type inference section.  See the updated
>
> https://go.googlesource.com/proposal/+/refs/heads/master/design/go2draft-type-parameters.md#type-inference
> section.
>
> 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+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/golang-nuts/CAOyqgcVvLvuAVy%3DWVA2n4wCcpEKNfbxTN-d_K%3Dz8kz1oiK9Z3g%40mail.gmail.com
> .
>

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CANjmGJujty1Xg03MttK4aFH_3GMs6BEQNWwZyfOwySKBv2_gnA%40mail.gmail.com.


Re: [go-nuts] Generics and parentheses

2020-07-22 Thread Steven Blenkinsop
On Wed, Jul 22, 2020 at 8:02 PM, Russ Cox  wrote:

> So it sounds like everyone is in favor of the entire generics proposal and
> all the semantics, and all we have left to hammer out is the bracket
> characters? Do I have that right?
>
> Best,
> Russ
>

I think this thread is specifically about the delimiters (first post is
about using square brackets instead of parentheses), but yeah, seems about
right.

I sort of wish interfaces allowed you to specify a receiver type rather
than requiring reflexive application (even where supported by syntax
sugar). Essentially:

type CustomOrdered interface(R) {
Less(other R) bool
}

instead of

type CustomOrdered[type T] interface {
Less(other T) bool
}

However, this is similar to type lists in interfaces in that it would make
the interface only usable as a constraint, since otherwise the receiver
type isn't known at compile time. The current design sidesteps this by
requiring you to specify a specific type argument in order to use the
interface as a type, even if the resulting interface type isn't terribly
useful. Reflexive application only works when using the interface as a
constraint.

>

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CANjmGJvZ3zbptYmFep%3Dex9uRbFEo16qvuUH_jL8aUqOLcA1mAA%40mail.gmail.com.


Re: [go-nuts] Generics and parentheses

2020-07-21 Thread Steven Blenkinsop
On Tue, Jul 21, 2020 at 3:12 PM, Michal Strba  wrote:

> I'd say a dot is necessary when instantiating a function call but
> unnecessary when instantiating a type because it's always syntactically
> clear when a type is required.
>

That's not true in Go. Conversions look like function calls:

  y := f(x)

could be a conversion or a function call, depending on whether f is a
function or a type. If you need to use type parameters on f, the same
parsing problems present themselves whether it's a parameterized type or a
type parametric function.

>

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CANjmGJsep6MaLPdGQ2KN6omtWp7Uv6sXC7%2BdpWSeQ2G9MMu-QA%40mail.gmail.com.


Re: [go-nuts] Re: [generics] Fuzzer, Type Switches

2020-07-19 Thread Steven Blenkinsop
On Sun, Jul 19, 2020 at 11:43 AM, Jake Montgomery 
wrote:

>  This seems to work: https://go2goplay.golang.org/p/8veymwXYCoZ
>
>
> I'm confused. It panics when I run it now.
>

Since the outcome is probably cached, I'm not sure how that could be the
case. Did you mean to respond to Ian's modified version?

On Jul 18, 2020, at 9:00 PM, Ian Lance Taylor  wrote:

> Compare that to https://go2goplay.golang.org/p/8U4h9flkhFN.
>

The point there is that the argument to the type parameter F is now
MyInt instead
of int. Since the underlying type is int, this satisfies the Primitive
constraint
on F. However, the switch in Randomize doesn't handle MyInt, so we hit the
default case, which panics.

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CANjmGJuSfqcaUxRYO4PTSKp5S0YvGb_zWnfyWXy6Upj6wBTMUw%40mail.gmail.com.


Re: [go-nuts] [generics] Fuzzer, Type Switches

2020-07-18 Thread Steven Blenkinsop


> On Jul 18, 2020, at 9:00 PM, Ian Lance Taylor  wrote:
> 
> On Sat, Jul 18, 2020 at 3:43 PM  wrote:
>> 
>> This seems to work: https://go2goplay.golang.org/p/8veymwXYCoZ
>> 
>> Still uses interfaces internally.
> 
> Compare that to https://go2goplay.golang.org/p/8U4h9flkhFN.
> 
> Ian

Seems like this should work, but it doesn't:
https://go2goplay.golang.org/p/TtRUrLG0Cdr

The draft says:
> Writing *T instead of T in a type parameter list changes two things. Let's 
> assume that the type argument at the call site is A, and the constraint is 
> Constraint (this syntax may be used without a constraint, but there is no 
> reason to do so).
> 
> The first thing that changes is that Constraint is applied to *A rather than 
> A. That is, *A must implement Constraint. It's OK if A implements Constraint, 
> but the requirement is that *A implement it.
> 

It appears the type constraint is being applied to int instead of *int here.

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/2DF07ABB-C03D-44D8-BCF2-0C3F76E39A09%40gmail.com.


Re: [go-nuts] [generics] Issues with identifying the matched predeclared type

2020-07-08 Thread Steven Blenkinsop
On Wed, Jul 8, 2020 at 3:59 AM roger peppe  wrote:

>
> That's another interesting syntax. I'm not sure whether there's any
> particular advantage in mentioning the type parameter in each case,
> although I guess it does mean that the syntax for multiple matches is
> straightforward and can allow an "any" match.


The meaning of case io.Stringer: in existing type switches is asymmetrical.
Matching is based on interface satisfaction (for interface constraints),
but the matched value has an exact type of io.Stringer inside the body of
the case. Choosing either exact matching semantics *or* constraint
refinement semantics for generic type switches will be inconsistent with
one of these two behaviours, potentially leading to confusion about what a
generic type switch is doing.

The advantage of mentioning the type parameter in each case is that it
makes the parallel to type parameter lists very obvious. If matching is
done on constraint satisfaction, then this syntax should suggest the
correct semantics. Also, just the fact that it's different from the
existing type switch case clause syntax helps avoid confusion between the
two.

Another advantage of mentioning the type parameter in each case is that
it allows you to change between T and *T constraints within the same
switch, as needed. Using constraints on *T could allow you to do exact type
matching as well:

type switch {
case *T interface{ type *string }:
// `T` is treated as identical to `string` in this case
case T io.Stringer:
// `T` can be any type that satisfies `io.Stringer` in this case
}


Maybe the type matching could be written using a shorthand like the one you
were suggesting, but with the opposite meaning:

type switch {
case *T type(*string):
// `T` is treated as identical to `string` in this case
}


(Or just case T = string: could work and would be more obvious, I suppose).

I'd hope that most people using type switches for specialisation would
> include a generic fallback for unknown types. The main use cases I see for
> it are optimisation and preserving backward compatibility.


Yeah, I was more thinking that if you *functionally required* the ability
to match to an exact type in order to implement your generic function, then
it wouldn't be total over its type parameter domain. For optimizations, I
can see how you might be relying on existing code that is only written to
support particular types for one reason or another.

On Wed, Jul 8, 2020 at 3:59 AM roger peppe  wrote:

>
>
> On Wed, 8 Jul 2020 at 00:33, Steven Blenkinsop 
> wrote:
>
>> On Tue, Jul 7, 2020 at 10:44 AM, roger peppe  wrote:
>>
>>>
>>> In my description, there's no assumption that doing it over the type
>>> parameter implies a refinement of the previously set type constraints. In
>>> fact it definitely implies otherwise because (for example) if you know that
>>> a generic type parameter has the known type "string", then it's a loosening
>>> rather than a tightening of the constraint - you can now do more things
>>> with values of that type than you could previously.
>>>
>>
>> I think this is speaking at cross purposes. The identity of the type is
>> more constrained (it must be string  as opposed to any other type
>> satisfying a particular interface), but you can do more with it in your
>> generic code. You're refining the constraint on the identity of the type
>> while at the same time expanding its capabilities. An unconstrained type
>> parameter can be any type but supports the fewest operations.
>>
>
> Fair point.
>
>
>>
>> I don't think it's sufficient. Consider this program:
>>> https://go2goplay.golang.org/p/wO0JHIuHH2l. If "string" matches both
>>> "myString" and "string" itself, then the type checker would allow the
>>> assignment of a function of type "func(string) uint64" to a function of
>>> type "func(myString) uint64" with no explicit type conversion, which breaks
>>> an important safety constraint in the language. Worse, if we let an
>>> interface type match any concrete type that happens to implement that
>>> interface, then there's a serious issue because those types probably don't
>>> have the same shape, so can't be used interchangeably. For example, this
>>> program would be valid, but isn't possible to compile because io.Stringer
>>> and string have different representations:
>>> https://go2goplay.golang.org/p/_uLjQxb-z-b
>>>
>>
>> I would think that in the second case, the assignment to xx wouldn't
>> type check because T is only known to implement io.Stringer rather than
>> being identical to io.Stringer.
>>
>
> That depends on the 

Re: [go-nuts] [generics] Issues with identifying the matched predeclared type

2020-07-07 Thread Steven Blenkinsop
ctly the same type.
>>> }
>>> }
>>>
>>>
>>> *Discussion*
>>>
>>> It might be a good idea to allow a type switch to specify a list of
>>> types rather than a single type, so several generic parameters can be
>>> specialized at the same time. For example:
>>>
>>> switch T, U {
>>> case int, string:
>>> }
>>>
>>>
>>> This is syntactically rather more useful than in a normal type switch,
>>> because there's no way to avoid nesting type switches (in a normal type
>>> switch, it's possible to assign the specialized value to another variable
>>> with wider scope, but that's not possible in general with generic type
>>> switches). However, it may be too confusing syntactically with the normal
>>> comma-list in a type switch statement which means "any of these types". A
>>> possible way of avoiding confusion that might be to require brackets:
>>>
>>> switch T, U {
>>> case (int, string):
>>> }
>>>
>>>
>>> The ability to use a concrete type directly in a  type(X) case is just
>>> syntax sugar for type(interface{type X}) and could be omitted. It
>>> depends how commonly used this might be.
>>>
>>>
>>> On Tue, 7 Jul 2020 at 04:51, Steven Blenkinsop 
>>> wrote:
>>>
>>>> On Mon, Jul 6, 2020 at 6:29 PM, roger peppe  wrote:
>>>>
>>>>>
>>>>> I've also been playing around in this area. I've been trying something
>>>>> similar to this approach: https://go2goplay.golang.org/p/sHko_EMhJjA
>>>>> But this isn't ideal - note that we lose type safety when assigning
>>>>> back to the generic hash function, because there's no way to let the
>>>>> compiler know that the actual type of the generic type parameter is known
>>>>> at that point.
>>>>>
>>>>> I also noticed an interesting wrinkle to doing a type switch on a
>>>>> value of the type:
>>>>>
>>>>> We can't do this:
>>>>>
>>>>>   case Hasher:
>>>>>   hi = func(t Hasher) uintptr {
>>>>>   return t
>>>>>   }
>>>>>
>>>>> because the actual type probably isn't Hasher - it's the actual type,
>>>>> not the interface type.
>>>>>
>>>>> If a type switch on a type argument was implemented (and I definitely
>>>>> support it) we'd have to think carefully about what semantics would be
>>>>> desired in this case - if one of the types is an interface type, would one
>>>>> get the usual interface-subtype rules for matching or not?
>>>>>
>>>>> For the record, I quite like the idea of using a separate syntax for
>>>>> type-based checking:
>>>>>
>>>>>type switch T {
>>>>>case int:
>>>>>case string:
>>>>>}
>>>>>
>>>>> That way, we could use exact-match rules for that construct without
>>>>> risk of confusion with the normal type switch rules, and perhaps the
>>>>> difference might make it clearer that T would change its type inside the
>>>>> body of the switch.
>>>>>
>>>> If the idea is to be able to refine the constraints on a type
>>>> parameter, then you need to be able to match based on "T satisfies
>>>> this interface". If you want to be able to match based on underlying type,
>>>> you could match against e.g. interface { type int }.
>>>>
>>>> I'm not sure how useful matching on a precise type is in this context.
>>>> Interfaces can't express exact type constraints as currently designed, so
>>>> exact type matching can't ever handle all cases. You'd need a really good
>>>> reason to be treating exactly one type out of the set with the same
>>>> underlying type differently in order for it to make sense.
>>>>
>>>> If you needed to, though, you could plausibly do it by:
>>>>
>>>> type switch *T {
>>>> case interface { type *fmt.Stringer }:
>>>> // T has to be the interface type `fmt.Stringer`
>>>> case interface { type *int }:
>>>> // T has to be the specific concrete type `int`
>>>> }
>>>>
>>>> Whether to support the following is what could potentially cause
>&

Re: [go-nuts] [generics] Issues with identifying the matched predeclared type

2020-07-06 Thread Steven Blenkinsop
On Mon, Jul 6, 2020 at 6:29 PM, roger peppe  wrote:

>
> I've also been playing around in this area. I've been trying something
> similar to this approach: https://go2goplay.golang.org/p/sHko_EMhJjA
> But this isn't ideal - note that we lose type safety when assigning back
> to the generic hash function, because there's no way to let the compiler
> know that the actual type of the generic type parameter is known at that
> point.
>
> I also noticed an interesting wrinkle to doing a type switch on a value of
> the type:
>
> We can't do this:
>
>   case Hasher:
>   hi = func(t Hasher) uintptr {
>   return t
>   }
>
> because the actual type probably isn't Hasher - it's the actual type, not
> the interface type.
>
> If a type switch on a type argument was implemented (and I definitely
> support it) we'd have to think carefully about what semantics would be
> desired in this case - if one of the types is an interface type, would one
> get the usual interface-subtype rules for matching or not?
>
> For the record, I quite like the idea of using a separate syntax for
> type-based checking:
>
>type switch T {
>case int:
>case string:
>}
>
> That way, we could use exact-match rules for that construct without risk
> of confusion with the normal type switch rules, and perhaps the difference
> might make it clearer that T would change its type inside the body of the
> switch.
>
If the idea is to be able to refine the constraints on a type parameter,
then you need to be able to match based on "T satisfies this interface". If
you want to be able to match based on underlying type, you could match
against e.g. interface { type int }.

I'm not sure how useful matching on a precise type is in this context.
Interfaces can't express exact type constraints as currently designed, so
exact type matching can't ever handle all cases. You'd need a really good
reason to be treating exactly one type out of the set with the same
underlying type differently in order for it to make sense.

If you needed to, though, you could plausibly do it by:

type switch *T {
case interface { type *fmt.Stringer }:
// T has to be the interface type `fmt.Stringer`
case interface { type *int }:
// T has to be the specific concrete type `int`
}

Whether to support the following is what could potentially cause confusion:

func F(type T interface { type int })(t T) {
type switch T {
case int:
...
}
}

Someone could plausibly believe this covers all possible cases, when it
doesn't cover type MyInt int, for example. This could either be disallowed
or picked up by a lint. Disallowing it would force the above workaround
syntax using pointer types in interface type lists. This is a bit kludgey,
but then it probably shouldn't be easier to do the thing which will more
often be wrong than the thing that will more often be right.

The other thing is that interface constraints as currently designed don't
really lend themselves to refinement in the first place. Sure, if you have
an interface with a type list, you can match on a subset of that type list,
but you can't ask whether a type "is in this type list *or* satisfies this
interface" or "satisfies at least one interface in this list". Easiest
solution might be to allow comma separated embedded interfaces:

type CustomOrdered(type T) interface {
Less(T) bool
}

type AnyOrdered(type T) interface {
constraints.Ordered, (CustomOrdered(T))
}

(I should also mention I don't really *like* having to define the
above interfaces so they have to be applied reflexively to work. The
fact that it will be done automatically in type parameter lists helps,
but it still feels wrong to have to do it. I understand that this is
to sidestep needing to add a second kind of generic type name in
interface definitions, though.)

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CANjmGJtp8osgT1xxPz-DdT9DF0c7-sWny2N9Ad60dFGLwUmadw%40mail.gmail.com.


Re: [go-nuts] [generic] Readibility of Multiple Parenthsis

2020-07-05 Thread Steven Blenkinsop
On Sun, Jul 5, 2020 at 12:22 PM, Jake Montgomery  wrote:

> I understand Ian's position of wait and see. But for completeness, I will
> point out that this new 'ambiguity' is different from the current cases
> where there would be a "collision
> between a variable name and a type name." As far as I can tell, any such
> collision in Go 1 would fail to compile. However, with the current
> parentheses based generics, such collisions could end up compiling, or
> failing to compile at a later location in a confusing way:
>

In an expression x(y)(z), x could be already be a type or a value and
successfully compile only to have unexpected results later on if there was
any confusion about what x refers to. What's changing is that y could also
now be a type or a value.

https://play.golang.org/p/jtxrrop7gP7

Ultimately, these kinds of examples are contrived. They're relying on
shadowing unexported identifiers with meaningless names in your own code,
and using the same name for a type vs. a value.

>

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CANjmGJvScUn5Uv5G66swrwwH_Y0diyNQ4-zMZcbRZjeQNqSOJw%40mail.gmail.com.


Re: [go-nuts] [generics] Interface as a contract criticism

2020-07-04 Thread Steven Blenkinsop
On Sat, Jul 4, 2020 at 5:50 PM  wrote:

> Both
>
> type X int | string
>
> and
>
> type X interface int, string
>
> Are meant to be a syntax sugar for:
>
> type X interface {
>  type int, string
> }
>
> It is not a sum type, but rather a generic type that needs to be
> instantiated before the use. That is why it cannot have a zero value:
>
> var x X // error, X must be instantiated before the use
>
> But i think one should not be able to write:
>
> type X interface {
>  type int
>  String() string
> }
>
> But instead it must be something like this:
>
> type X interface {
>  type int, fmt.Stringer
> }
>
> Or:
>
> type X interface int, fmt.Stringer
>
> Or:
>
> type X interface int, interface{String() string}
>
> https://go2goplay.golang.org/p/fNqNeDyM3R9
>
> I do understand that this is kinda the same case like x.Name (complex
> literals in contracts), but in my opinion it would bit a bit more
> consistent syntax, wouldn't it?
>

Not really more consistent. Consider:

type I interface {
type A, B
C
}

The constraint this represents could be logically expressed as (type A |
type B) & (interface C), where type constraints require the underlying
types to match, and interface constraints require the interface to be
satisfied. By writing this as interface A, B, C, you're erasing both the
distinction between a type constraint and an interface constraint, as well
as the distinction between X & Y and X | Y. That would make your
alternative syntax *inconsistent* to my mind.

>

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CANjmGJtdtXoPQhXxkeFrKpTc-jNTFZAEttnq0rK54%2BPRJ7Nj9g%40mail.gmail.com.


Re: [go-nuts] Generics: type-list vs method-based constraints -- not orthogonal?

2020-07-03 Thread Steven Blenkinsop
On Fri, Jul 3, 2020 at 3:16 PM, Ian Lance Taylor  wrote:

>
> The trick with this kind of approach is understanding what should
> happen if the type with a package-specified method is converted to an
> empty interface type, handed to some other package, and then in some
> way handed back to the original package.  Does the package-specified
> method survive these conversions?  Why or why not?  Also, how does
> type reflection work: can it discover such methods?  Can it discover
> them in a different package?  There may be answers here but they don't
> jump out as obvious.
>

In order to be consistent, the package-qualified method should survive
conversions the same way as a normal method would. Even unexported methods
do this. Interface satisfaction is a property of the type, not the value.
This would require that packages have the ability to register any extension
methods they define in the runtime representation of an external type
somehow. However, package-qualified methods would never satisfy an
unqualified method constraint in an interface, regardless of any interface
conversions.

Reflection would be able to discover these methods, provided the package
defining them is linked into the binary. Importing a package for its side
effects is already a thing, so that aspect shouldn't be too surprising. You
also don't have the same visibility concerns you have with unexported
methods; there's no particular issue with a package discovering an
extension method defined in a different package at runtime.

One thing that I've found tricky is how to deal with embedding. If these
methods can be promoted, then you have method instances which no single
package owns. The package that defines a struct embedding a type and a
package defining extension methods on the same type don't necessarily know
about each other.

I would think that, in order to have extension methods be promoted, it
would need to be done explicitly. If you could embed a type like pkg(T) which
layered the extension methods defined in package pkg on top of the inherent
methods of type T, then extension methods wouldn't need to be promoted in
the general case. Otherwise, extension methods most likely just wouldn't be
promoted.

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CANjmGJt5NHHPU%2BR86GOyRYp1DgEHfZCB5PzbfRQoMTmMtV34mg%40mail.gmail.com.


Re: [go-nuts] [generics] use interfaces in type lists

2020-07-03 Thread Steven Blenkinsop
On Fri, Jul 3, 2020 at 3:05 PM, Ian Lance Taylor  wrote:

>
> Using an interface type in a type list has a defined meaning: the type
> argument must have as its underlying type that interface type.  It
> doesn't mean what I think you want it to mean, which is to serve as a
> union of the type lists of the interface types.  What you suggest
> would not be impossible, but it would mean making an exception to the
> rules for type lists.


One way to disambiguate would be to define a pseudo-type, I(T) for some
interface type I and type T which is identical to T if T implements I, and
is otherwise an empty type that doesn't match any other type. This could
also solve the type switching on type parameters question, since

switch t := t.(type) {
case interface { type int }(T):
   ...
}

would match for a value t of type T if the underlying type of T is int. The
syntax is a bit unwieldy, but it makes it clear that we're matching based
on the type-list semantics and disambiguates between matching to an
interface type vs. matching to a concrete type that implements an
interface. That it looks like a conversion shouldn't be too much of an
issue, since generic functions are also to be followed by either a type
list or a value list.

These pseudo-types would probably only make sense in type lists and type
switches, just as null is only usable as a pseudo-type in type switches.

There might be cleaner ways of doing this, though.

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CANjmGJtcJXYsprLD1f6mMJ5ZYW4xaAJgCFhaC5cBM2M4AxvJJg%40mail.gmail.com.


Re: [go-nuts] Generics: type-list vs method-based constraints -- not orthogonal?

2020-07-02 Thread Steven Blenkinsop
Passing in two type parameters, one which is the type used by the caller
and one which implements the interface, would almost work if conversions
were allowed between type parameters with the same underlying types:

https://go2goplay.golang.org/p/ylchcyACuV7

You have to double parameterize everywhere explicitly, though. I'm not
quite clear what the advantage would be compared to passing in the
comparator, other than the tradeoffs for static vs. dynamic.

Another option for abstracting over builtin and custom type cases would be
to add namespaced extension methods. Basically, a package could add methods
to a builtin type which are namespaced by the package, and then interfaces
could qualify their method names with the particular package whose methods
they want to use. Downstream packages would be able to satisfy these
methods only for the types they define, like with normal "free" methods.
This change would potentially have a far reaching impact, but it would
sidestep needing to add a lot of names to the language.

type CustomOrdered(type T) interface {
package.Less(other T) bool
}

func (x int) package.Less(y int) bool {
return x < y
}

It would be nice if you could do this for all types that implement
constraints.Ordered in one definition, but that's a whole other can of
worms.

One way to address this would be if you could
On Thu, Jul 2, 2020 at 7:59 PM, ben...@gmail.com  wrote:

> Hi folks,
>
> This thread  on
> lobste.rs made me wonder if the difference between type-list constraints
> and method-interface constraints is going to cause a bunch of issues or
> code duplication. There's a lack of orthogonality here that makes me uneasy.
>
> For example, the Smallest() function in this proposal takes a slice of
> []T, where T is "type T constraints.Ordered", a type-list based constraint.
> That means Smallest() will only work with the built-in types specified in
> the type list (or types with one of those as an underlying type), and can't
> be used with more complex struct types.
>
> For it to work for other types, you'd have to write a second version of
> Smallest() -- code duplication -- that took a method-interface based
> constraint like so:
>
> type CustomOrdered(type T) interface {
> Less(other T) bool
> }
>
> Arguably Smallest() would still be quite useful even if it only works for
> builtin integer and float point types, but with the type-list Ordered it
> wouldn't work for (say) big.Int, a custom Decimal type, or a more complex
> struct type.
>
> But I think this is worse for ordering-based *data structures* like Tree
> of T. If done with the type-list Ordered, the tree could only store
> built-in types, which isn't that useful. Using a constraint like
> CustomOrdered would work and be more flexible ... but then a basic
> Tree(int) wouldn't work. You'd have to do Tree(MyInt) and convert
> everything from int to MyInt on the way in, and MyInt back to int on the
> way out -- a bunch of type conversion boilerplate.
>
> Or you'd end up writing two versions of your generic Tree: BuiltinTree
> that uses Ordered (type lists), and CustomTree that uses CustomOrdered
> (interface with Less). Not very nice.
>
> (Here's some Go2Go code which shows this for Smallest:
> https://go2goplay.golang.org/p/Rbs374BqPWw)
>
> I'm not sure how the proposal solves this for something like Smallest()
> ... I don't think it does. For ordered data structures, like the Map
> example, it passes in a custom "compare" function to the initializer and
> kind of side-steps the issue. Which isn't bad for data structures as it'd
> still eliminate a lot of code, but it would be kind of a pain for little
> algorithms like Smallest().
>
> Thoughts?
>
> -Ben
>
> --
> 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+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/golang-nuts/7f471eba-be08-4d32-a50a-22939f63b76dn%40googlegroups.com
> 
> .
>

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CANjmGJs8F3m1DrGh6mzGngvCP%3DYBr4EPbiKfc8XAoRgK%2BrZY6A%40mail.gmail.com.


Re: [go-nuts] Re: Contracts Draft: why are method pointers allowed

2019-08-06 Thread Steven Blenkinsop
This text seems somewhat contradictory:

The function Init cannot be instantiated with the type MyInt, as that type
> does not have a method Set; only *MyInt has Set.
>

...

>
If a method is listed in a contract with a plain T rather than *T, then it
> may be either a pointer method or a value method of T.
>

The intent seems to be that a contract that constrains *T is *more specific*
than a contract that constrains T. It requires the conditions needed for
initialization, on both the caller and callee side.

It's the inability to make a sufficiently specific contract that makes the
current choice to allow calling pointer methods on values based on a T
constraint
unfortunate. Initialization is an important use case, but so is updating,
and being able to rely on consistent behaviour when it comes to methods
that update the receiver—for both the caller and generic callee—makes code
easier to reason about. Interfaces get this right and it would be a shame
to lose it with generics.

The use case I posted earlier—of being able to update values in a slice
using a pointer method—would be nice to have supported as well, but not at
the expense of the more common case. I'm not sure what the answer is.
Perhaps contracts could allow you to use a pseudo-type like  denoting
addressable T values, and let the compiler figure out matching up levels of
indirection between generic code and the methods it calls, but this might
add more complexity to the design than it's worth.

On Mon, Aug 5, 2019 at 7:55 AM,  wrote:

> For those who haven't already noticed, I thought I'd point out that the
> draft design has now been changed (as Ian intimated it might be) so that
> contracts may now require a pointer method in some cases i.e. if the type
> parameter is T one can now specify that *T has a certain method.
>
> In particular, this will be needed if an implementing function is
> declaring a variable of type T but you then need to invoke a method on it
> where the receiver type is *T. To understand why this is so, one needs to
> re-read the design paper which has some examples of why the previous
> situation didn't work.
>
> Looked at overall I think this is a better idea than what I was proposing
> earlier, though it might be difficult for folks to get their heads around
> the circumstances when and why a pointer method is needed. However, as it's
> probably a situation which will arise infrequently in practice, it should
> not be a major concern.
>
> Alan
>
> --
> 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+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/golang-nuts/64567134-2fec-423c-8828-fed14f392fc7%40googlegroups.com
> 
> .
>

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CANjmGJswmnFkA7pHCLDhBF24ttcSVxBD%2BjPsdEKpH_GA4sPk9g%40mail.gmail.com.


Re: [go-nuts] Generics Draft: Mixing types and methods.

2019-08-03 Thread Steven Blenkinsop
On Sat, Aug 3, 2019 at 2:11 AM, Ian Lance Taylor  wrote:

> You're right, I wrote it wrong.  Actually I'm not sure how to write that
> contract.  Ideally we want to say that T is either comparable or has the
> Equal(T) bool method, but there is no way to write that.  We can embed
> comparable(T), but we can't do that in a disjunction with Equal(T) bool.


So I guess I was building castles in the sky, then. Though, just allowing
this does seem like a viable option. I would guess that the reason not to
allow disjunction between contracts or between constraints on different
types is so that whether each type satisfies a contract can be decided
without reference to the constraints on any other type. Allowing
disjunction between single-parameter contracts applied to the same type
would preserve this property, and the syntax of using these contracts as
constraints would make the restriction that they have to be applied to the
same type fall naturally out of the syntax. You lose the property that the
constraints for any particular type parameter are already in conjunctive
normal form, but you already need to do normalization to check the
conjunctive normal form against the disjunctive normal form in order to
determine whether one contract allows its parameter to satisfy another
contract (when calling generic code from generic code).

As for the generic contracts I was showing, they would be very useful if
this were allowed, but I can understand the teachability hazard of having
two kinds of type parameters on a single declaration. The draft already has
two kinds of type parameters, since contract parameters are different from
regular type parameters, but as long as you never have both kinds of
parameters in play, people don't necessarily need to understand the
distinction between them.

On Sat, Aug 3, 2019 at 2:11 AM, Ian Lance Taylor  wrote:

> On Fri, Aug 2, 2019 at 9:25 PM Steven Blenkinsop 
> wrote:
> >
> > On Fri, Aug 2, 2019 at 6:55 PM 'Axel Wagner' via golang-nuts <
> golang-nuts@googlegroups.com> wrote:
> >>
> >>
> >> contract Comparable(T) {
> >>   T comparable, Equal(T) bool
> >> }
> >
> >
> > Wait, does this work? I mean, `comparable` is a contract, but it's being
> used as a constraint.
>
> You're right, I wrote it wrong.  Actually I'm not sure how to write
> that contract.  Ideally we want to say that T is either comparable or
> has the Equal(T) bool method, but there is no way to write that.  We
> can embed comparable(T), but we can't do that in a disjunction with
> Equal(T) bool.
>
>
> > The same issue comes up with the
> >
> > switch T.(type) { ... }
> >
> > idea. Even if you're only constraining one type at a time like this, you
> might still need to express a relationship to another type parameter.
> Unless this is allowed:
> >
> > switch (type) {
> > case comparable(T): ...
> > case Equaler(T): ...
> > }
>
> I suspect that switch T.(type) would have to only permit disjunctions
> listed in the contract for T.
>
> 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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CANjmGJsTFyOMFC5i_5UM5Vpb%2Bpfu-YLkAAmNnMRTkhp_jyKMAg%40mail.gmail.com.


Re: [go-nuts] Generics Draft: Mixing types and methods.

2019-08-02 Thread Steven Blenkinsop
On Fri, Aug 2, 2019 at 6:55 PM 'Axel Wagner' via golang-nuts <
golang-nuts@googlegroups.com> wrote:

>
> contract Comparable(T) {
>   T comparable, Equal(T) bool
> }
>

Wait, does this work? I mean, `comparable` is a contract, but it's being
used as a constraint. Could you also write:

contract Equaler(T) {
T Equal(T) bool
}

>
contract Comparable(T) {
T comparable, Equaler
}

? Or is comparable just special? Or does this not actually work, even for
comparable? This would certainly be convenient if you could do it, though
it means contracts involving a single type are privileged over others (you
can create a disjunction between constraints, but not between contracts,
for example). It seems like if you can create contract constraints like
this, you'd also want to be able to make *generic* contract constraints, to
capture things like

contract Appender(type Elem)(T) {
T Append(...Elem) T
}

contract Appendable(type Elem)(T) {
T []Elem, (Appender(Elem)) // Parens to avoid parsing like a method
constraint
}

The same issue comes up with the

switch T.(type) { ... }

idea. Even if you're only constraining one type at a time like this, you
might still need to express a relationship to another type parameter.
Unless this is allowed:

switch (type) {
case comparable(T): ...
case Equaler(T): ...
}

On Fri, Aug 2, 2019 at 6:55 PM 'Axel Wagner' via golang-nuts <
golang-nuts@googlegroups.com> wrote:

> FWIW:
> interface{}(a) == interface{}(b)
> would work. It would panic if a and b have the same, non-comparable type.
> But if you know the type is equal and comparable, it's well-defined and
> does what you want. So you have to modify your code a bit:
>
> type equaler(type T) interface {
>   Equal(T) bool
> }
>
> contract Comparable(T) {
>   T comparable, Equal(T) bool
> }
>
> func Compare(type T Comparable)(a, b T) bool {
>   if eq, ok := a.(equaler(T)); ok {
> return eq.Equal(b)
>   }
>   // Okay, this is weird, but: If you have `func (*T) Equal(T) bool`, a T
> (value) would
>   // be accepted by the contract, as contracts don't distinguish between
> value and
>   // pointer-receivers. But it would fail above type-assertion, as values
> don't include
>   // pointer-methods in their method set.
>   if eq, ok := ().(equaler(T)); ok {
> return eq.Equal(b)
>   }
>   return interface{}(a) == interface{}(b)
> }
>
> I can't think of anything in the current design draft preventing this from
> working (though I'm sure Ian can correct me if I'm wrong).
>
> It's a special case for equality-comparison though, it doesn't generalize
> to any other operators.
>
> On Fri, Aug 2, 2019 at 10:40 PM Bruno Albuquerque  wrote:
>
>> Ok, it makes sense. I do think that supporting something like this might
>> make the proposal even more appealing as it will bring custom types
>> somewhat closer to builtin types by allowing generic functions/methods that
>> can act on both at the same time.
>>
>> On Fri, Aug 2, 2019 at 1:28 PM Ian Lance Taylor  wrote:
>>
>>> On Fri, Aug 2, 2019 at 1:12 PM Bruno Albuquerque  wrote:
>>> >
>>> > I was thinking about a way to  "extend" usual operations (say,
>>> equality checks) to types that can not be compared the usual way (they are
>>> not "comparable" in the contract sense) and came up with something like
>>> this:
>>> >
>>> > // Just to use for type assertion later.
>>> > type Equaler interface {
>>> >   Equal(Equaler) bool
>>> > }
>>> >
>>> > contract Comparable(T) {
>>> >   T comparable(T), Equal(T) bool
>>> > }
>>> >
>>> > func Compare(type T Comparable)(a, b T) bool {
>>> >   if eq, ok := a.(Equaler); ok {
>>> > return eq.Equal(b)
>>> >   }
>>> >
>>> >   return a == b  // Does this work at all?
>>> > }
>>> >
>>> > Would this work? More specifically it looks to me that that if the
>>> specific type is not comparable (But has the Equal method), the compiler
>>> might see the "==" comparison in the function and give an error.
>>> >
>>> > One way around this would possibly be to use something similar to type
>>> assertion (in this case, a and b would have to be asserted to "comparable"
>>> which I guess is not possible as it is a contract). Or, the compiler could
>>> be smart enough to know that if we reached that check, then the type must
>>> be comparable (so it would also not give an error).
>>>
>>> In the current design draft, that would not work.  The == operator is
>>> not supported by all possible types, so it is not permitted.
>>>
>>> We definitely don't want to rely on the compiler being smart enough.
>>> Any such approach would require writing down the exact inference rules
>>> that the compiler is permitted to use.  Otherwise different compilers
>>> would behave differently.
>>>
>>> One possibility we've toyed with is
>>>
>>> switch T.(type) { // Note: switch on type parameter itself, not a
>>> value of that type.
>>> case Equaler:
>>> ...
>>> case comparable:
>>> // Permit using == operator here on values of type 

Re: [go-nuts] Re: Contracts Draft: why are method pointers allowed

2019-08-01 Thread Steven Blenkinsop
On Thu, Aug 1, 2019 at 6:35 AM, Max  wrote:

> Thus it would require 'T' to be a pointer - namely '*big.Int' - to match.
> It would mean that the receiver itself of the contract 'T Cmp(other T)
> int' is a pointer. Is it a case allowed by contracts?
>

Yes, this is something which is supported be contracts. But this does raise
the point that the ability to try and fudge over whether `T` or `*T` (where
`T` is a contract parameter) satisfies a method constraint is limited by
the fact that constraint parameters can appear in multiple positions in a
given method signature, and only one of those places (the receiver) has
conventionally allowed auto-referencing. Also, it doesn't matter much that
`Cmp` can be in the method set of both `A` and `*A` (where `A` is a
concrete value type) when only one of those types will be identical to the
type the `other` method parameter, so only one type can satisfy the
contract.

Personally, I think the implication of this is that contract method
constraints should be based on method sets, i.e. `A` can't satisfy a
contract using a method defined on `*A`, just like with interfaces.

This does rule out being able to write the generic function I showed above,
where we want to be able to accept a slice of either `A` or `*A`, and call
`*A` methods without needing to know which type is represented by the type
parameter. I'm not sure how strong the desire to support this sort of use
case is. Forcing you to use a `[]*A` in this case would be slightly
unfortunate (or `[]A` and `*T DoStuff()`, but that would require that `T`
be a value type).

This case could technically be handled with some rather more involved uses
of contracts, like

contract Slice(S, Elem, Base) {
S []Elem
S Index(int) *Base
*Base DoStuff()
}

You'd just need two helper types to wrap your slice, one where `Elem` and
`Base` are identical, and one where `Elem` is identical to *Base.

It's unfortunate that you'd need to specify `Elem` and `Base` in the
signature of any function using this contract, given that they can be
inferred from `S`, but I'm not sure whether there'd be any willingness to
add associated types to the design, i.e.

contract Slice(S) {
type S.Elem
type S.ElemBase
S []S.Elem
S Index(int) *S.ElemBase
*S.ElemBase DoStuff()
}

On Thu, Aug 1, 2019 at 6:35 AM, Max  wrote:

> I think that a single syntax allowing both pointer receivers and value
> receivers - with no mechanism to distinguish them - creates unnecessary
> ambiguity, and in some cases it can concretely be a problem.
>
> Consider the following example, adapted from 'math/big.Int`:
> ```
> contract Comparable(T) {
>   // return -1 if receiver is lesser than 'other'
>   // return +1 if receiver is greater than 'other'
>   // return 0 if they are equal
>   T Cmp(other T) int
> }
> ```
> it seems perfectly reasonable yet, depending on the exact semantics of
> contracts, `math/big.Int` may have troubles satisfying it, because its
> method 'Cmp' has the signature
> ```
> func (recv *big.Int) Cmp(other *big.Int) int
> ```
> Thus it would require 'T' to be a pointer - namely '*big.Int' - to match.
> It would mean that the receiver itself of the contract 'T Cmp(other T)
> int' is a pointer. Is it a case allowed by contracts?
> And how does it interact with the rule that both pointer receivers and
> value receivers are allowed?
>
>
> If you ignore for a moment the ability of contracts to specify a union of
> types,
> I prefer my proposal https://github.com/cosmos72/gomacro#generics where
> contracts are just generic interfaces,
> and they can *optionally* specify the receiver type - used in case you
> want to *remove* the ambiguity between pointer and value receiver types.
> They clearly require the possibility to specify multiple contracts in a
> generic type or function signature, while the current proposal
>
> https://go.googlesource.com/proposal/+/master/design/go2draft-contracts.md#methods
> allows only a single contract in a in a generic type or function
> signature, thus requiring contracts to be able to specify the methods of
> several unrelated types.
>
> --
> 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+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/golang-nuts/cf04c27c-6ac0-4b64-96b4-f0e7a1a2a99d%40googlegroups.com
> 
> .
>

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 

Re: [go-nuts] Contracts Draft: why are method pointers allowed

2019-07-29 Thread Steven Blenkinsop
On Mon, Jul 29, 2019 at 2:25 PM, Ian Lance Taylor  wrote:

> The motivation is to avoid requiring contracts to specify whether a method
> is a pointer method or a value method, just as we do not require interface
> types to specify whether a method is a pointer method or a value method.
>

I'm not sure whether pointer method vs. value method is the distinction
that needs to be made. For the general purpose of writing code that calls
methods on arbitrary types, what we want to know is whether a
type-parameterized function should assume it needs an addressable value or
if it can use a non-addressable value of the parameter type to call a
method. Any references/dereferences that need to be done can be done
automatically as long as you know whether the value needs to be addressable
and the code is written accordingly (i.e. without needing to take the
address of an implicit variable). That might end up being represented in
the language as though you're passing pointers into the methods, but I
don't think that needs to map to whether the concrete method itself accepts
a pointer or a value.

To illustrate, if you have

func Foo(type T ...)(slice []T) {
 for i := range slice {
 slice[i].DoStuff()
 }
}

what sort of bound do you need on `T` so that it can handle each
combination of:

1. `T` is passed a value type `Arg` or a pointer type `*Arg`, and
2. `DoStuff` is defined on `Arg` or on `*Arg`?

Why you sort of want is a constraint like

HasDoStuff(T), HasDoStuff(*T)

where at least one or the other should capture the `DoStuff` method in each
case, and thus the combined constraint should allow you to call methods
on/involving addressable `T` values (potentially based on the fiction that
the accepted type is `*T`). I'm not sure what the best way of write such a
constraint is, though, or how common this kind of case is.

On Mon, Jul 29, 2019 at 2:25 PM, Ian Lance Taylor  wrote:

> On Mon, Jul 29, 2019 at 7:05 AM Ilia Choly  wrote:
> >
> > When converting a non-pointer value to an interface, pointer methods
> cannot be used to satisfy the interface. Even though the compiler could add
> instructions to take the value's address, this is not allowed because it's
> error prone. Since pointer methods usually mutate the receiver, you don't
> want to be operating on a copy. https://play.golang.org/p/XDiki8_uHMs
> >
> > When reading the contracts proposal, I'm confused by the seemingly
> contradictory decision to allow pointer methods.
> https://go.googlesource.com/proposal/+/master/design/go2draft-contracts.md#methods
> >
> >> In order to avoid worrying about the distinction between value methods
> and pointer methods, in a generic function body all method calls will be
> pointer method calls. If necessary, the function body will insert temporary
> variables, not seen by the user, in order to get an addressable variable to
> use to call the method ...This makes it easier to understand which types
> satisfy a contract, and how a contract may be used. It has the drawback
> that in some cases a pointer method that modifies the value to which the
> receiver points may be called on a temporary variable that is discarded
> after the method completes. It may be possible to add a vet warning for a
> case where a generic function uses a temporary variable for a method call
> and the function is instantiated with a type that has only a pointer
> method, not a value method.
> >
> >
> > The same example converted to use interfaces fails
> https://play.golang.org/p/FBbXQw7dKL6 What's the motivation for this
> design decision?
>
> The motivation is to avoid requiring contracts to specify whether a
> method is a pointer method or a value method, just as we do not
> require interface types to specify whether a method is a pointer
> method or a value method.  It does make it possible to write certain
> kinds of bugs, but it's not clear how much that arises in practice.
>
> That said, it's likely that we will have to modify contracts to
> require a pointer method in some cases, in order to separate defining
> a variable of some type with invoking pointer methods on that
> variable, so I would not be surprised if this aspect of the design
> draft is changed.
>
> 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+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/golang-nuts/CAOyqgcWgzkqS4GHH%2BbcQd6KNGJrRd1v2d0D2GU5LsomJF0SL%3Dw%40mail.gmail.com
> .
>

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 

Re: [go-nuts] Allow methods on primitives

2019-06-09 Thread Steven Blenkinsop
>
> If one library defines string.Render() for html, and another defines
> another string.Render() for, say, a graphics library, which Render will be
> called when I call "str".Render()?


Method call syntax is the least of the worries. Presumably, that could be
based on which packages are imported in the calling context, and you'd get
an error if it's ambiguous. The larger problem is when you get interfaces
involved. Two Content variables storing the same value of type string could
have different implementations of Render depending on where the interface
value was created. And if a variable v of type Content is used in a way
equivalent to interface{}(v).(Content), you could end up changing the
implementation of Render or failing the assertion altogether. So, the
problem with allowing an arbitrary package to define methods on primitive
types isn't with method call syntax, it's with using such methods to
satisfy an interface like Content.

One workaround would be to allow you to use package-qualified method names,
so

package foo

type Content interface {
package.Render()
}

func (s string) package.Render() { ... }

At minimum, package-qualified methods defined in other packages couldn't be
used to satisfy Content. Normal Render methods defined in other packages
(for types which have to be defined in those packages) could be allowed to
satisfy the interface, and/or other packages could be allowed to define
methods like

func (t T) foo.Render() { ... }

for their own types to satisfy the interface.

There hasn't been much interest in pursuing anything like this for Go,
however. Something like the sum types mentioned by Bakul might be a better
match for existing Go idioms, since it could be a swap-in replacement for
interface{} in existing functions that use a type switch with an interface
fallback, allowing them to better specify which types they support. Of
course, there's also been opposition to adding sum types, since many see
interfaces as "good enough" to cover the use cases of sum types.

On Fri, Jun 7, 2019 at 3:00 PM Burak Serdar  wrote:

> On Fri, Jun 7, 2019 at 12:40 PM Michael Ellis 
> wrote:
> >
> > Count me among those who love the language just the way it is and regard
> the prospect Go 2.0 with dread and loathing born of the Python 3 experience.
> >
> > That being said, there's one itty-bitty change I'd like to advocate:
> Allow methods on primitives.
> >
> > I think I understand why allowing new methods on external packages is a
> bad idea because it introduces a form of the fragile superclass problem.
> But surely there's nothing fragile about strings, ints and floats.
> >
> > Being unable to define a method on a string is *not* a showstopper since
> one can always do "type Foo string" or use type-assertions. It's just that
> it's inelegant in the case of a function that takes a recursive struct as
> an argument if the leaves of the tree are strings.  For example
> >
> > type HTMLTree struct {
> > tag string
> > attributes string
> > content * Content //
> > }
> >
> > type Content interface {
> >Render()
> > }
> >
> > // NOT ALLOWED
> > func (s  string) Render() {
> > }
> >
> > So I have to do something like
> >
> > type SC string
> > func (s SC) Render() {
> > }
> >
> > but that means instead of being able to write
> >
> > Div("", P("id=1", "When in the course of ..."))
> >
> > one must use the wrapper type on every content string.
> >
> > Div("", P("id=1", SC("When in the course of ...")))
> >
> > Not the end of the world, but uglier than it ought to be, IMO.
> >
> > Is there a way to get around this or, failing that, an explanation of
> why methods on primitives are verboten?
>
> If one library defines string.Render() for html, and another defines
> another string.Render() for, say, a graphics library, which Render
> will be called when I call "str".Render()?
>
> >
> > Thanks!
> >
> >
> >
> >
> >
> >
> > --
> > 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+unsubscr...@googlegroups.com.
> > To view this discussion on the web visit
> https://groups.google.com/d/msgid/golang-nuts/6daa53b9-c2e6-48e8-b022-c8339d3b8dbc%40googlegroups.com
> .
> > For more options, visit https://groups.google.com/d/optout.
>
> --
> 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+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/golang-nuts/CAMV2Rqo6vMmEOxTzp%2BB2AJXc-ZUuSpNP-7p0AYMoRd86-hR2Bg%40mail.gmail.com
> .
> For more options, visit https://groups.google.com/d/optout.
>

-- 
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, 

Re: [go-nuts] In-Method declaration of array of struct literals vs global var?

2019-06-06 Thread Steven Blenkinsop
= is always required when you're assigning a value to the var. the
confusion might be that you can also have a declaration like

var bar []struct{a, b, c string}

where you don't assign a value to bar (meaning it will be null).

Really, the syntax is

var variableName Type = value

You can leave off either the "Type" or the "= value" but not both.

var bar = []struct{a, b, c string} {
  { "really", "long", "row"},
  { "many", "many", "rows"},
  ...
}

is just a special case where you've left off the "Type", and "value"
happens to be a composite literal expression. It could also be written as

var bar []struct{a, b, c string} = []struct{a, b, c string} {
  { "really", "long", "row"},
  { "many", "many", "rows"},
  ...
}

On Thu, Jun 6, 2019 at 2:47 PM 'Aaron Spangler' via golang-nuts <
golang-nuts@googlegroups.com> wrote:

> Thank you!  You are correct.  That was exactly my problem.  Adding the
> equals sign (=) solved it.
>
> I guess I need to be more aware that sometimes an equals statement is
> required on a 'var' line and other times it is not.  (perhaps only when it
> has a literal)
>
> Thanks again!
>
> On Thu, Jun 6, 2019 at 11:05 AM Ian Lance Taylor  wrote:
>
>> On Thu, Jun 6, 2019 at 10:56 AM ajs via golang-nuts
>>  wrote:
>> >
>> > I can declare literal bar inside a function like this:
>> >
>> > func foo() {
>> >   bar := []struct{a, b, c string} {
>> > { "really", "long", "row"},
>> > { "many", "many", "rows"},
>> > ...
>> >   }
>> > }
>> >
>> > But I really want it anchored (for code generation reason) outside of a
>> function like this:
>> >
>> > func foo() {
>> >   ...
>> > }
>> >
>> > var bar []struct{a, b, c string} {
>> >   { "really", "long", "row"},
>> >   { "many", "many", "rows"},
>> >   ...
>> > }
>> >
>> > The problem is it gets upset on the last character of the 'var bar ...'
>> line.  Is there a better way to write this?
>> > Note for reasons outside of this discussion, I really want to avoid
>> writing it by repeating the discrete field names:
>> >
>> > var bar []struct{a, b, c string} {
>> >   {a: "really",b: "long",c: "row"},  // Don't want to do this
>> >   {a: "many", b: "many", c: "rows"}, // Don't want to do this
>> >   ...
>> > }
>> >
>> > Any thoughts?  What am I missing?
>>
>> An important tip: when asking a question, please tell us precisely
>> what you did and precisely what happened.  You can see what happened,
>> but when you write "it gets upset" we have to guess.  And it's easy
>> for us to guess wrong.
>>
>> When I look at
>>
>> var bar []struct{a, b, c string} {
>>   { "really", "long", "row"},
>>   { "many", "many", "rows"},
>>   ...
>> }
>>
>> what I think is that it should say
>>
>> var bar = []struct{...
>>
>> That is, you are missing the "=".  But I don't know if that was a typo
>> in the e-mail message.  So if that doesn't help tell us exactly what
>> you did and exactly what happened.
>>
>> 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+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/golang-nuts/CAHP%2Bjq4-wp5EgvmK-POEHmDNa8-T9WUJqzAYJA9jRsuuo6%2Boaw%40mail.gmail.com
> 
> .
> For more options, visit https://groups.google.com/d/optout.
>

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CANjmGJsibJ5qVZ%3DTMW6FOU6VJtVKHP4uFjkN6wyf-sU8QOWrTg%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.


Re: [go-nuts] Re: Generic types - functions and methods on instantions

2018-09-11 Thread Steven Blenkinsop
On Tue, Sep 11, 2018 at 5:46 PM, Ian Lance Taylor  wrote:

>
> While methods can be a convenient way to organize code, their only
> real semantic meaning is to satisfy interfaces.


They also represent a limited form of type-directed function overloading. A
package can contain multiple methods with the same name as long as they
have different receiver base types. And because of how interfaces and
embedding work, we can even think of exported methods as inhabiting
universal scope.

While the main utility of "overloading" a method name is to allow different
types to satisfy the same interface, with the contracts proposal they can
also serve to allow multiple types to satisfy the same contract. Even with
Roger Peppe's more limited contracts counterproposal, methods that can't
satisfy interfaces could be required based on a method expression call
without needing to deal with all the ambiguities of permitting ordinary
method call syntax.

Allowing generic methods to be specified in contracts by using method
expressions has the property that a contract could only require particular
instantiations of a particular method, so a contract couldn't require, say,
`T.M(U)(t, ...)` for any type `U`, but instead only for particular type
arguments. This simplifies the problem of needing to provide a runtime hook
for different instances of the method—you only need the ones specified by
the contract—and removes the full generality that might creep too close to
allowing C++-style metaprogramming.

>

-- 
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+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [go-nuts] Link: Getting specific about generics

2018-09-04 Thread Steven Blenkinsop
On Tuesday, September 4, 2018 at 6:07:32 PM UTC-4, xingtao zhao wrote:

> I was assume that generic interfaces are allowed, which we do not need 
> "self" type.

 

This is *not* equivalent. If you have an interface defined as

 
type Fooer(type T) interface {
 Foo() T
}


this corresponds to a contract written as

 
contract Fooer(s S, t T) {
 interface{ Foo() T }(s)
}


You have two separate type parameters when you're really just trying to 
talk about a single type. You had to write it like this because your 
language is poorly designed. When using the interface, you'd always have to 
write 

 
func DoFoo(type T Fooer(T)) ...


Requiring a generic trait to be used reflexively just so you can talk about 
operations involving multiple values with the same type isn't a good 
design. If would be like saying "we don't have to be able to name the 
receiver variable inside a method because we can always pass the receiver 
value as a separate parameter, like v.String(v)!". This is technically 
true, but if your language is designed like this, I don't want to use it. 
Requiring type constraints to be written like this is the same. You can't 
use the unfamiliarity of a new feature to justify making decisions that 
would be clearly bad ones in a more familiar context.

 

> In terms of convertableTo, it can be put into the operator category, which 
> will be implicitly retrieved from the function body. 

 

"Can" and "should" are two different things. Assume when reading my 
previous and current response that I'm talking about a design where all 
operators and conversions supported by a type parameter have to be 
specified by its contract/interface constraint and can't be implied by the 
body of the function. Having only a partially specified interface makes it 
very easy to accidentally change the interface of your function by, for 
example, calling a function which directly or indirectly performs an 
operation not previously present in your code.

 

> In general, a given concrete type could only satisfy this interface one 
>> way. Having
>
>  
>
> type IntAndFloatTaker interface {
>
>  Taker(type int)
>
>  Taker(type float)
>
> }  
>
>
> I think this is still not allowed, as they have the same function name 
> while different types.

 

That's my point. I'm saying that this could be a useful property. Given a 
parameterized interface I and a type parameter T that implements I(U), 
there can only be exactly one value of U for a given T. This could be used 
to assist type inference. If an interface can contain conversions, however, 
then there are multiple ways the same type can satisfy that interface—since 
a type can support conversions to multiple different types—which means this 
property wouldn't hold. I know you don't think conversions should go in 
interfaces/contracts, but I disagree, so here we are. This property also 
wouldn't hold if generic methods were added to the language. 
Hypothetically, *if* you could have


type Setter(type T) interface {
 Set(T)
}

type S struct{}
func (s S) Set(type T C)(t T) { ... }


and *if* this allowed S to satisfy Setter(T) for any type T that satisfies C, 
then the above property wouldn't hold. The current proposal doesn't suggest 
this, and I think it's probably incompatible with the design goal of 
being implementation agnostic, but it would create a problem if this 
functionality were ever enabled in the future and the previous behaviour 
had been used to inform type inference. The solution used by other 
languages to solve this dilemma is to have type aliases in their equivalent 
of interfaces:


type Setter interface {
 type T
 Set(T)
}

type S struct{}
func (s S) Set(type T C)(t T) { ... }

// This would fail to compile because the compiler can't
// infer the identity of `Setter.T` for `S` based on 
// `S.Set`, since the method can work for any type `T`
// that satisfies `C`:
//
// var _ Setter = S{}
//


Note that my intent here is just to explore the design space. I'm not sure 
whether this is a direction the Go team would be willing to go.

On Tuesday, September 4, 2018 at 6:07:32 PM UTC-4, xingtao zhao wrote:
>
>
>
> On Tuesday, September 4, 2018 at 2:26:58 PM UTC-7, Steven Blenkinsop wrote:
>>
>> If we try to translate contracts into interfaces, the first thing we run 
>> into is that there's no way to refer to the dynamic type of the interface. 
>> Compare:
>>
>>  
>>
>> contract Fooer(t T) {
>>
>>  interface{ Foo() T }(t)
>>
>> }
>>
>>  
>>
>> to
>>
>>  
>>
>> type Fooer interface {
>>
>>  Foo() ???
>>
>> }
>>
>>  
>>
>> There would have to be some sort of self type:
>>
>>  
>>
>> type Fooer interface {
>>

Re: [go-nuts] Link: Getting specific about generics

2018-09-04 Thread Steven Blenkinsop
If we try to translate contracts into interfaces, the first thing we run
into is that there's no way to refer to the dynamic type of the interface.
Compare:



contract Fooer(t T) {

 interface{ Foo() T }(t)

}



to



type Fooer interface {

 Foo() ???

}



There would have to be some sort of self type:



type Fooer interface {

 Foo() self

}


Let's say there's a built in convertibleTo constraint


type FooConvertible interface {

 convertibleTo(int)

 Foo() self

}



For one thing, this looks like a method. (Aside: This is a problem in the
existing generics proposal as well if generic interfaces are allowed, since
interface embedding would become ambiguous.) Presuming that we solve this
ambiguity, there's a deeper challenge. If I have a generic interface:



type Taker(type T) interface {

 Take() T

}



In general, a given concrete type could only satisfy this interface one
way. Having



type IntAndFloatTaker interface {

 Taker(type int)

 Taker(type float)

}



wouldn't work because the same type can't implement both func (...) Take()
int and func (...) Take() float. convertibleTo (and convertibleFrom) would
be unique in this regard, and could get in the way of (say) being able to
infer the type parameters of



func Take(type T, U Take)(t T) U { t.Take() }



T can be inferred from the argument, and you ought to be able to infer U
from T, since T can only implement Taker(type U) for exactly one U. But, if
convertibleTo exists, this isn't true in general.


This doesn't address operators. You could have builtin constraints for each
operator, or each set of operators. Or you could have some sort of builtin
method corresponding to each operator. These are certainly doable, but
designing and naming the constraints/methods is a whole undertaking which
the contracts draft seeks to avoid.

On Tue, Sep 4, 2018 at 12:52 PM xingtao zhao  wrote:

> My five cents:
>
> 1) the methods of the type template are defined by interface style
> 2) operators are retrieved implicitly from function body
> 3) function-calls inside are also retrieved implicitly from the function
> body
>
> For graph example, we may declare it as:
>
> type Edgeser(type E) interface {
> Edges() []T
> }
> type Nodeser(type N} interface {
> Nodes() from, to N
> }
> type Graph(type Node Edgers(Edge), type Edge Nodeser(Node)) struct { ... }
>
>
> On Monday, September 3, 2018 at 4:19:59 PM UTC-7, Ian Lance Taylor wrote:
>
>> On Sun, Sep 2, 2018 at 1:08 AM, 'Charlton Trezevant' via golang-nuts
>>  wrote:
>> >
>> > Link: [Getting specific about generics, by Emily
>> > Maier](https://emilymaier.net/words/getting-specific-about-generics/)
>> >
>> > The interface-based alternative to contracts seems like such a natural
>> fit-
>> > It’s simple, straightforward, and pragmatic. I value those aspects of
>> Go’s
>> > philosophy and consider them to be features of the language, so it’s
>> > encouraging to see a solution that suits them so well. The author also
>> does
>> > a great job of contextualizing the use cases and debate around
>> generics,
>> > which I found incredibly helpful.
>> >
>> > Any thoughts?
>>
>> It's a very nice writeup.
>>
>> It's worth asking how the graph example in the design draft would be
>> implemented in an interface-based implementation.  Also the syntactic
>> issues are real.
>>
>> 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+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
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+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [go-nuts] Re: An issue with the select statement.

2018-05-11 Thread Steven Blenkinsop
There's a reason Go doesn't support non-random selects. Often, you'll be
selecting on channels which peers are accessing concurrently. In this
situation, there's no ordering guarantee between when different cases will
become available. If case 2 can become available ever-so-slightly before
case 1, or ever-so-slightly after, then which case will be selected ends up
random. However, if the scheduler happens to schedule the peer for case 1
and doesn't schedule the peer for case 2 until the peer for case 1 blocks,
then this could give a false appearance of determinism, and someone could
write code depending on a race condition by accident. Also, you could end
up with a situation where the peer for case 2 is under-serviced because the
peer for case 1 is always waiting when the select statement is executed.

Your situation is odd because there *is* an ordering guarantee between when
the select cases become available, because there's only one sender. In that
case, you'd really only need one channel except that you're sending two
different types of requests, whose meaning is partially determined by what
channel they're sent on. You could instead use a single channel and avoid
select entirely with

struct Request { Work: *WorkItem; Idle: bool }

You could then send Request{ Work: NewWorkItem() } or Request{ Idle: true } (or
maybe Request{ Idle: responseChannel }) over a single channel and not have
to worry about trying to bend select into a different shape.

On Fri, May 11, 2018 at 12:36 PM T L  wrote:

>
>
> On Friday, May 11, 2018 at 11:54:16 AM UTC-4, Jake Montgomery wrote:
>>
>> As others on this thread have pointed out, this use case does not
>> actually require select where the cases are checked in order.
>>
>> However, for completeness, if you need to check two channels, and they
>> must be checked in order, then use two select statements with defaults:
>> for {
>> select {
>> case wi := <-work_ch:
>> self.do_the_work(wi)
>> default:
>> }
>> select {
>> case <-self.idle_request:
>> self.idle_response <- true
>> default:
>> }
>> }
>>
>>  Again, this should rarely be necessary, or even useful. But there it is.
>>
>
>
> Good point, but it is too cpu consuming.
> I think the following one is better.
>
>   for {
>
>   select {
>   case <-self.idle_request:
>   self.idle_response <- true
>   default:
>   }
>
>
>   select {
>
>   case wi := <-work_ch:
>   self.do_the_work(wi)
>   case <-self.idle_request:
>   self.idle_response <- true
>   }
>   }
>
> But I think if it would be even better if Go support non-random select
> blocks.
>
>
>
>>
>>
>> On Friday, May 4, 2018 at 10:24:56 AM UTC-4, Andriy Pylypenko wrote:
>>>
>>> Hi,
>>>
>>> I have a scenario which I haven't found a way to implement with the Go
>>> channels and select statement while it's no problem to do it with the
>>> select()/poll() functions. The scenario is as follows.
>>>
>>> Let me use a Go-like pseudo-code to demonstrate the idea. There is a
>>> source of a work items which are processed by several goroutines. Here is
>>> the source procedure:
>>>
>>> work_ch := make(chan *WorkItem)
>>>
>>> for {
>>> work_ch <- NewWorkItem()
>>> }
>>>
>>> And here is the worker thread:
>>>
>>> for {
>>> wi := <-work_ch
>>> self.do_the_work(wi)
>>> }
>>>
>>> Now I need to suspend the work. I stop supplying the work items and want
>>> to make sure the worker goroutines are done with the work. The source
>>> procedure becomes something like this:
>>>
>>> for {
>>> if suspend_requested {
>>> for _, worker := range workers {
>>> worker.idle_request <- true
>>> }
>>> for _, worker := range workers {
>>> <-worker.idle_response
>>> }
>>> report_suspend_is_success()
>>> wait_until_unsuspended()
>>> }
>>> work_ch <- NewWorkItem()
>>> }
>>>
>>> And I want to modify the worker thread like this:
>>>
>>> for {
>>> select {
>>> case wi := <- work_ch:
>>> self.do_the_work(wi)
>>> case <-self.idle_request:
>>> self.idle_response <- true
>>> }
>>> }
>>>
>>> However this last snippet of code does not work because the cases within
>>> the select statement are randomly chosen when both channels are ready so I
>>> have no guarantee that the first case is executed first.
>>>
>>> Talking about the select() or poll() functions from the C library which
>>> evidently were an inspiration for the Go select statement, there is no
>>> problem with the described approach. It's because the select() function
>>> returns a complete information about the state of all the monitored
>>> descriptors and allows the programmer to decide what he wants to read or
>>> write and in which order, based on readiness of every descriptor.
>>>
>>> I think it would be a great idea to have some function similar 

Re: [go-nuts] Re: Go could really use a while statement

2018-05-03 Thread Steven Blenkinsop
loop could be used as syntax for Roger Peppe's loop:

  loop if x = next(); x != nil {
...
  }

I guess you could also call that for if, but that makes me think of

  for if me, ok := i().(OscarMayerWeiner); ok {
 for _, person := range everyone {
 love[person] = me
 }
  }

On Thu, May 3, 2018 at 3:56 PM  wrote:

> These threads are akin to bike shedding thus a waste of time.
>
>
> In storytelling relief is part of good tragedy.
>
> I consider the overloading of for to be a plus because for, while,
> do-while are just loops with conditions. Maybe ‘loop’ is a more Go-like
> keyword.
>
> loop i, e := range c {
>
> Matt
>
> On Thursday, May 3, 2018 at 8:46:36 AM UTC-5, M P r a d e s wrote:
>>
>> Can anybody point me to a single discussion on golang-nuts that led to a
>> significant syntax change? These threads are akin to bike shedding thus a
>> waste of time.
>>
>> Adding while provide nothing of value in a language that supports basic
>> looping. And for those who compare if and switch arguing it is equivalent,
>> you can't do type switches with an if statement.
>>
>> This is discussion is going nowhere.
>>
> --
> 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+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
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+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [go-nuts] Why does assigning a function variable to a method value allocate memory?

2017-08-23 Thread Steven Blenkinsop
On Wed, Aug 23, 2017 at 6:20 AM Bakul Shah  wrote:

> This is a Mealy machine, where the next state
> depends on the current state and current input (in s/w not
> much use for a Moore machine unless you are driving/simulating
> some regular physical process, in which case you don't need
> any input parameter).
>

This is a Moore machine. In a Moore machine, the next state can depend on
both the current state and the inputs, but any *output* being produced
during a given state can only depend on the state. Note that the next state
is not considered to be an output of the machine.

A Mealy machine would be producing an output throughout its operation which
responds in real time to changes to the inputs, where the relationship
between the inputs and the output depends on the state of the FSM. In order
to have a Mealy machine in software, you'd either need to be polling the
inputs between state transitions to keep the output up to date, or
represent the "output" as a function value which gets called with the
polled inputs whenever the output is polled.

-- 
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+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [go-nuts] Re: Go 2 suggestion - Types like "int?"

2017-08-22 Thread Steven Blenkinsop
Other places where Go relies on every type having a zero value:

// Making slices with non-zero length.
s := make([]*int, 10)

// Reslicing a slice beyond its length.
s := make([]*int, 0, 10)[:10]

// Eliding fields from a composite literal.
p := struct { x: int; y: *int } { x: 5 }
s := []*int { 10: new(int) }

// Initializing an array programmatically.
var arr [10]*int
for i := range arr { ... }

// Accessing a non-existent map entry.
v := m["non existent"]

// Reading from a closed channel.
v := <-ch

// Comma-ok.
// Without zero values, the type of `v` is in each case
// something like `ok ? *int : uninitialized`.
v, ok := m["string"]
v, ok := i.(*int)
v, ok := <-ch


On Tue, Aug 22, 2017 at 8:59 AM  wrote:

> I would like to echo on Tong Sun's suggestion here. I know his isn't an
> "experience report" per se, but a suggestion worth building on, for those
> who're wishful of optionals in Go.
>
> The case mentioned might be immediately solvable by just using a pointer
> to the variable, which gives you the ability to assign nil (json null) to
> it. However, *T is *not* syntactic sugar for Optional. Pointers come
> across as "just as good as optionals" when needed because we don't have
> another [built-in] option. Not to mention, pointers have more than
> nil-assignability to them.
>
> I understand that we can just write a generic generator for Optional
> for whatever type we want an optional wrapper for. This is something I've
> always done when absolutely needed (most of the time with proto3 Protobuf).
>
> func main() {
> msg := pboptional.NewString()
>
> fmt.Println("msg:", msg).// => msg: nil
>
> msg.From("hello world")
>
> fmt.Println("msg:", msg) // => msg: Optional("hello world")
>
> if msg, ok := msg.Unwrap(); ok {
> // some
> fmt.Println("msg:", msg) // => msg: hello world
> } else {
> // none
> fmt.Println("msg is nil")
> }
> }
>
> There are obvious advantages to using optionals, including safely defining
> variable. However, on the contrary, Go is currently, and by-design so, not
> in the best shape to adopt optional types. For optionals to be a viable in
> core, non-optionals would have to (?) guarantee a value (and not just
> assumed zero-value when left uninitialized). This is for the compiler to
> deliver the type-safety promise of optionals *and* non-optionals. In
> other words, it means that we would have to not allow uninitialized types
> to be zero-value. I mean, what good is supporting optional types, if the
> non-optionals don't require you to set their values?
>
> Consider this currently valid Go code:
>
> func getAge() (int, error) {
> var age int
> return age, errors.New("ERR") // age is assumed zero-value
> }
>
> func main() {
> age, err := getAge() // => 0, ERR
> }
>
> With optionals implemented (how I'm imagining), this would become:
>
> // uninitialized non-optional should not compile
> // i.e. don't assume zero-value
> func getAge() (int, error) {
> var age int
> return age, errors.New("ERR") // => compile error: variable age is
> not initialized
> }
>
> // this should work instead
> func getAge() (int?, error) {
> var age int?
> return nil, errors.New("ERR")
> }
>
> func main() {
> age, err := getAge() // => Optional(nil), ERR
> }
>
> But every method that also returns an error, should not necessarily have
> an accompanied optional type, like `(int?, error)`. There's so much in Go
> that can be nil (or nil like zero-values), and isn't necessarily fit to be
> considered optional, like nil interfaces and pointers.
>
> We're also going to have to reconsider the phrase "errors are just values"
> if we want to pair non-optional types with error in the return types. Take
> the following suggestion (inspired from Swift):
>
> func getAge() (int, throws error) {
> var age int
> throw errors.New("ERR")
> // we're not returning anything and it compiles
> // i.e. throw *is* return but only for error
> }
>
> func main() {
> age := try getAge() // => panic("ERR")
> }
>
> func main() {
> // although getAge() returns a non-optional, it
> // gets is automatically wrapped in an optional
> // when using `try?`.
> //
> // basically we're trading error for nil value.
> age := try? getAge() // => Optional(nil)
> }
>
> func main() {
> // this is the graceful way to get non-optional result
> // and handle error, if any.
> try {
> age := getAge()
> } catch error {
> fmt.Println(err.Error()) // => ERR
> }
> }
>
> Therefore, if considered, optionals would be a *huge* undertaking to
> implement (and practice) in Go source, while also delivering the promise
> optionals bring.
>
> Let me know if you have a better syntax/suggestion than try catch blocks
> (for returning only an error; no zero-values for 

Re: [go-nuts] Why does vet's 'rangeloop' check only check the last statement of a loop?

2017-08-10 Thread Steven Blenkinsop
If you have a loop like:

for i := range slice {
f()
}

There's no way to know whether f launches a goroutine that captures the
loop variable without also evaluating the body of f and potentially every
function directly or indirectly called by f. If i  escapes into a global
variable, you also have to evaluate the entire program to see if a
goroutine is ever launched which could access i by way of that
variable. This is what they mean by whole program analysis.

However, I feel like only catching a go or defer statement which is the
last statement in the loop body is very far from a best effort. I also
wonder if the analysis could take advantage of the existing escape analysis
in the compiler to flag likely misuses of loop variables. There are
certainly valid use cases for loop variables escaping (such as when this
coincides with returning from the function or otherwise breaking the loop),
so I'm not sure how easy it would be to discriminate, even if it's feasible
to begin with.

On Thu, Aug 10, 2017 at 1:18 PM  wrote:

> I've noticed that cmd/vet's rangeloop check, which warns you about binding
> to range loop variables in function literals which are launched with 'go'
> or 'defer', is more limited than I thought:
>
>
> https://github.com/golang/go/blob/d5ad7793d610bddfb3e7e09b8dafa0b0837f0cb2/src/cmd/vet/rangeloop.go#L6-L9
>
>
> 
>
>> This file contains the code to check range loop variables bound inside
>> function literals that are deferred or launched in new goroutines. We only
>> check instances where the defer or go statement is the last statement in
>> the loop body, as otherwise we would need whole program analysis.
>>
>
> I don't understand why whole program analysis is necessary here. Why can't
> cmd/vet check each function literal declared within the loop's braces?
>
> --
> 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+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
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+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [go-nuts] Why is reflect.ValueOf(nil map).Interface() != nil?

2016-08-08 Thread Steven Blenkinsop
Perhaps for clarity, the trip through reflect is a red herring. All you
need is to put the map in an interface:

package main
>
> import (
> "fmt"
> )
>
> func main() {
> var m map[string]interface{}
> if m != nil {
> panic("m != nil")
> }
> var i interface{} = m
> if i == nil {
> // I expect this.
> fmt.Println("OK")
> } else {
> // This is what happens.
> fmt.Printf("nil != %# v\n", i)
> }
> // output:
> // nil != map[string]interface {}(nil)
> }
>

The reason the interface is non-nil in this case is described in Ian's link.

On Mon, Aug 8, 2016 at 1:27 PM Ian Lance Taylor  wrote:

> On Mon, Aug 8, 2016 at 10:07 AM, Sam Salisbury 
> wrote:
> > The code speaks for itself, I thought I was understanding reflection up
> > until this point... It seems that the zero value of maps is nil, until
> you
> > round-trip them to a reflect.Value, and they become non-nil.
>
> This is an instance of https://golang.org/doc/faq#nil_error .
>
> 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+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
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+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.