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] 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] Re: Contracts Draft: why are method pointers allowed

2019-08-01 Thread Max
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.


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

2019-07-30 Thread 'Axel Wagner' via golang-nuts
Ah, thanks, I think I understand now. AIUI this would essentially require
that the author of a generic function or type would have to write a
contract to specifically allow or disallow pointer/value receivers to
satisfy the contract?

I personally don't really like the idea of putting that decision on the
implementer of a generic type or function - for pretty much the same reason
I don't want to know whether an interface-implementation uses pointer or
value receivers. All I (the implementer of a function taking the interface)
care is that they satisfy the API I require. I can't tell you (the
implement of that interface) whether you should do that via a pointer, a
basic type, an empty struct or a slice.

So IMO it's fine, for all operations I could wish to do with a pointer
(channel, slice, map…) to explicitly put that in my function signature.
Method calls are kind of an exception to that though - I still only care
about being able to call that method, just like with interfaces, but to do
that I *need* to know whether it's a pointer or value receiver. That's why
I think the exception from the design for that case is kind of justified
(even if a bit unfortunate) - specifically because it allows the
implementer of the generic function to ignore a distinction that is only
meaningful to its caller.

I do kind of agree with OP though, that it would seem more logical to just
require the caller to pass a pointer, when a pointer is required, just as
we do with interfaces. But weak opinions :)

On Tue, Jul 30, 2019 at 9:58 PM  wrote:

>
> On Tuesday, July 30, 2019 at 7:47:05 PM UTC+1, Axel Wagner wrote:
>>
>> On Tue, Jul 30, 2019 at 8:31 PM  wrote:
>>
>>> My suggestion was that you can't use a pointer type as a type parameter
>>> if the latter is subject to a contract.
>>>
>>
>> I'm not sure I understand you. Wouldn't that preclude using a generic map
>> with pointers as keys?
>>
>
> No, it wouldn't preclude that but the key would need to expressed as a *K
> rather than a K, if K were subject to a contract. As a pointer type it
> would automatically follow that *K was comparable.
>
>>
>>
>>> In the case you mention, the contract could be expressed as a
>>> disjunction of value and pointer methods:
>>>
>>> contract stringer(T) {
>>>T String() string, *T String() string
>>> }
>>>
>>
>> Currently, Disjunctions only apply to a single type. You can't form
>> expressions like this.
>> IMO that's a good restriction to maintain. Because the more powerful the
>> contract language becomes, the harder it'll be to make it useful.
>>
>
> Well, currently you can't use *T as a method receiver type in a contract
> so this would be a necessary exception to that rule if my suggestion were
> adopted.
>
> However, I agree with your general point that the restriction should be
> maintained in all other circumstances.
>
>>
>>
>>> On the other hand and more generally, not knowing whether the type
>>> parameter represented a pointer or a value might lead to some awkward
>>> coding. For example, you wouldn't be able to de-reference the type argument
>>> as it might not be a pointer.
>>>
>>
>> If a generic function wants to de-reference an argument, it should
>> specify that as a pointer: func f(type T) (p *T)
>> This is the same as with slices, maps, channels, functions or any
>> composite type - you can't express "type parameter T should be a slice of
>> some kind", because you are instead expected to just specify []T if you
>> want a slice.
>>
>
> Yes, but if T happened to be a pointer to some type, then *T would be a
> double pointer to that type. As the design currently stands, you'd have no
> way of knowing whether T was a pointer or not unless the contract specified
> that it was one of the predefined types.
>
> What I was trying to suggest here is that it would be helpful in some
> circumstances to know whether T was or was not a pointer type which would
> be a by-product of my suggestion.
>
> 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/cb9b37fc-19d4-4d25-bac8-72da1ade20a5%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/CAEkBMfHvNm9Azg1rHph5J4vmAEsz3ONWsQRFyry4yJXz%3DZiqAQ%40mail.gmail.com.


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

2019-07-30 Thread Henrik Johansson
Why make any distinction between pointers and non pointers? Isn't the
(usual) point to allow the caller to decide upon instantiation?
We define a contract in terms of an unknown set of types and then let
whoever uses it fullfil the contract however they want?

On Tue, Jul 30, 2019, 21:57  wrote:

>
> On Tuesday, July 30, 2019 at 7:47:05 PM UTC+1, Axel Wagner wrote:
>>
>> On Tue, Jul 30, 2019 at 8:31 PM  wrote:
>>
>>> My suggestion was that you can't use a pointer type as a type parameter
>>> if the latter is subject to a contract.
>>>
>>
>> I'm not sure I understand you. Wouldn't that preclude using a generic map
>> with pointers as keys?
>>
>
> No, it wouldn't preclude that but the key would need to expressed as a *K
> rather than a K, if K were subject to a contract. As a pointer type it
> would automatically follow that *K was comparable.
>
>>
>>
>>> In the case you mention, the contract could be expressed as a
>>> disjunction of value and pointer methods:
>>>
>>> contract stringer(T) {
>>>T String() string, *T String() string
>>> }
>>>
>>
>> Currently, Disjunctions only apply to a single type. You can't form
>> expressions like this.
>> IMO that's a good restriction to maintain. Because the more powerful the
>> contract language becomes, the harder it'll be to make it useful.
>>
>
> Well, currently you can't use *T as a method receiver type in a contract
> so this would be a necessary exception to that rule if my suggestion were
> adopted.
>
> However, I agree with your general point that the restriction should be
> maintained in all other circumstances.
>
>>
>>
>>> On the other hand and more generally, not knowing whether the type
>>> parameter represented a pointer or a value might lead to some awkward
>>> coding. For example, you wouldn't be able to de-reference the type argument
>>> as it might not be a pointer.
>>>
>>
>> If a generic function wants to de-reference an argument, it should
>> specify that as a pointer: func f(type T) (p *T)
>> This is the same as with slices, maps, channels, functions or any
>> composite type - you can't express "type parameter T should be a slice of
>> some kind", because you are instead expected to just specify []T if you
>> want a slice.
>>
>
> Yes, but if T happened to be a pointer to some type, then *T would be a
> double pointer to that type. As the design currently stands, you'd have no
> way of knowing whether T was a pointer or not unless the contract specified
> that it was one of the predefined types.
>
> What I was trying to suggest here is that it would be helpful in some
> circumstances to know whether T was or was not a pointer type which would
> be a by-product of my suggestion.
>
> 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/cb9b37fc-19d4-4d25-bac8-72da1ade20a5%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/CAKOF695ayjMH7fE_OFd_gu414zxK6Co%3DWK0sNYwUvYr4SyD0hw%40mail.gmail.com.


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

2019-07-30 Thread alan . fox6
 
On Tuesday, July 30, 2019 at 7:47:05 PM UTC+1, Axel Wagner wrote:
>
> On Tue, Jul 30, 2019 at 8:31 PM > wrote:
>
>> My suggestion was that you can't use a pointer type as a type parameter 
>> if the latter is subject to a contract.
>>
>
> I'm not sure I understand you. Wouldn't that preclude using a generic map 
> with pointers as keys?
>

No, it wouldn't preclude that but the key would need to expressed as a *K 
rather than a K, if K were subject to a contract. As a pointer type it 
would automatically follow that *K was comparable.

>  
>
>> In the case you mention, the contract could be expressed as a disjunction 
>> of value and pointer methods:
>>
>> contract stringer(T) {
>>T String() string, *T String() string
>> }
>>
>
> Currently, Disjunctions only apply to a single type. You can't form 
> expressions like this.
> IMO that's a good restriction to maintain. Because the more powerful the 
> contract language becomes, the harder it'll be to make it useful.
>

Well, currently you can't use *T as a method receiver type in a contract so 
this would be a necessary exception to that rule if my suggestion were 
adopted.

However, I agree with your general point that the restriction should be 
maintained in all other circumstances.

>  
>
>> On the other hand and more generally, not knowing whether the type 
>> parameter represented a pointer or a value might lead to some awkward 
>> coding. For example, you wouldn't be able to de-reference the type argument 
>> as it might not be a pointer.
>>
>
> If a generic function wants to de-reference an argument, it should specify 
> that as a pointer: func f(type T) (p *T)
> This is the same as with slices, maps, channels, functions or any 
> composite type - you can't express "type parameter T should be a slice of 
> some kind", because you are instead expected to just specify []T if you 
> want a slice.
>

Yes, but if T happened to be a pointer to some type, then *T would be a 
double pointer to that type. As the design currently stands, you'd have no 
way of knowing whether T was a pointer or not unless the contract specified 
that it was one of the predefined types.

What I was trying to suggest here is that it would be helpful in some 
circumstances to know whether T was or was not a pointer type which would 
be a by-product of my suggestion.

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/cb9b37fc-19d4-4d25-bac8-72da1ade20a5%40googlegroups.com.


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

2019-07-30 Thread 'Axel Wagner' via golang-nuts
On Tue, Jul 30, 2019 at 8:31 PM  wrote:

> My suggestion was that you can't use a pointer type as a type parameter if
> the latter is subject to a contract.
>

I'm not sure I understand you. Wouldn't that preclude using a generic map
with pointers as keys?


> In the case you mention, the contract could be expressed as a disjunction
> of value and pointer methods:
>
> contract stringer(T) {
>T String() string, *T String() string
> }
>

Currently, Disjunctions only apply to a single type. You can't form
expressions like this.
IMO that's a good restriction to maintain. Because the more powerful the
contract language becomes, the harder it'll be to make it useful.


> On the other hand and more generally, not knowing whether the type
> parameter represented a pointer or a value might lead to some awkward
> coding. For example, you wouldn't be able to de-reference the type argument
> as it might not be a pointer.
>

If a generic function wants to de-reference an argument, it should specify
that as a pointer: func f(type T) (p *T)
This is the same as with slices, maps, channels, functions or any composite
type - you can't express "type parameter T should be a slice of some kind",
because you are instead expected to just specify []T if you want a slice.


>
> It's clearly an area where some more thought is needed as Ian intimated
> earlier.
>
> 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/302c6d33-a8ea-4e8a-b02b-7cff1b3de1c5%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/CAEkBMfHPNF6n%2Bc3%2BipqO-nh1%3DeTLstoxnUS_UOKiHRaPX1Yoog%40mail.gmail.com.


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

2019-07-30 Thread alan . fox6
My suggestion was that you can't use a pointer type as a type parameter if 
the latter is subject to a contract.

In the case you mention, the contract could be expressed as a disjunction 
of value and pointer methods:

contract stringer(T) {
   T String() string, *T String() string
}

However, if T were used as an ordinary/return parameter type, you would 
need two functions - one for T and one for *T - and so may be it is too 
restrictive.

On the other hand and more generally, not knowing whether the type 
parameter represented a pointer or a value might lead to some awkward 
coding. For example, you wouldn't be able to de-reference the type argument 
as it might not be a pointer.

It's clearly an area where some more thought is needed as Ian intimated 
earlier.

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/302c6d33-a8ea-4e8a-b02b-7cff1b3de1c5%40googlegroups.com.


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

2019-07-30 Thread roger peppe
On Tue, 30 Jul 2019 at 14:58,  wrote:

> One way of avoiding this muddle between pointer and value methods would be
> to require that any type parameter (T say) which is subject to a contract
> cannot be replaced by a pointer type.
>

What do you mean by this? Do you mean you can't use a pointer type as a
type parameter? That would seem rather restrictive to me.
For example, AFAICS it would mean you couldn't have a single function that
is able to call a String method on both `*big.Int` and `reflect.Type`.

-- 
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/CAJhgachqD_dG1QWG9CG3zudzCCuJ_ctKK2MWMdQbk8Kp1aW0Gw%40mail.gmail.com.