I've thought of some other ways of excluding 'string' so that one could 
restrict an 'exclude' constraint to just numeric types.

At the expense of adding another line, you could do:
   int(T)

or if (say) T * T implied T + T, T - T and T / T (which would certainly be 
true) then you could use that instead of T + T.

However, if stuff were used in the contract for which there was no analog 
in the function code itself, it would inevitably introduce some opacity and 
anyone comparing the contract with the function, who was unaware of such 
hacks, might wonder why on earth that had been done.

On the other hand, it would provide some future-proofing as one might later 
introduce a function which did use the * operator and could then reuse the 
same contract rather than writing another one.

Alan

On Sunday, October 21, 2018 at 12:21:46 AM UTC+1, alanfo wrote:
>
> I think it's fair to say that dealing with untyped numeric constants is 
> one of the most opaque areas of the draft design and I remember thinking 
> when I first read it that a clearer and more intuitive solution would have 
> to be found.
>
> As far as the 'excluded types' idea is concerned, I can't really think of 
> any other use cases apart from numeric ranges though it's worth noting in 
> my paper I had this example:
>
> contract add1K(T) {
>     T + T
>     T(unsigned int)
>     exclude{string, int8, uint8}(T)  // can't add a thousand to these 
> }
>
> where I had to explicitly exclude 'string' because it supports both the + 
> operator and a conversion from any integer value.
>
> Alan
>
> On Saturday, October 20, 2018 at 11:36:02 PM UTC+1, Ian Denhardt wrote:
>>
>> Quoting alan...@gmail.com (2018-10-20 16:59:52) 
>>
>> >    I haven't checked them all but I did notice one example which your 
>> >    paper doesn't appear to cover, namely the add1K example which has 
>> been 
>> >    a stumbling block for a lot of proposals including my own though I 
>> did 
>> >    eventually find a way of dealing with it. 
>>
>> This is a fair point. I have a couple of initial thoughts, but will 
>> think about it. The contract there actually brings up my other big 
>> complaint about contracts besides non-orthogonality; they are not a good 
>> expression of intent. For reference: 
>>
>>     contract add1K(x T) { 
>>         x = 1000 
>>         x + x 
>>     } 
>>
>> While it's possible to piece together what has to be true about a type 
>> to satisfy this contract, it's really not obvious at the outset what the 
>> point of it is. Looking at the contracts in the draft design, I feel 
>> like I would generally speaking have to jump through mental hoops to 
>> understand what concepts were being expressed by a given contract. 
>>
>> >    1. If interfaces were used, a way would need to be devised to 
>> express 
>> >    that a type supports a particular operator or operators. To be 
>> >    compatible with methods something like the following seems best: 
>> >    � � �  +(T, T) T 
>> >    However, this would mean that someone writing an interface to be 
>> used 
>> >    for generic constraint purposes would have to know and write out the 
>> >    signature for each operator used. 
>>
>> This seems like a relatively minor problem. Eric sketched out a possible 
>> syntax, here is another: 
>>
>>     type Ordered[type T] interface { 
>>         operator < (other T) bool 
>>     } 
>>
>>     func (MyType) operator < (other T) bool { ... } 
>>
>> (where `operator` becomes a keyword) 
>>
>> I'm not convinced having to remember the type signatures is a 
>> problem -- for most operators they are fairly self-evident, and we 
>> already have to do this for a wide range of interfaces in the standard 
>> library. I think adding a whole new concept to the language is a much 
>> bigger cognitive load. 
>>
>> >    2. As your own paper clearly shows, it is possible to deal with 
>> >    multiple type parameters which refer to each other using an 
>> interface 
>> >    based approach and even the draft design paper itself admits this is 
>> >    possible. However, it seems to me to be less elegant than a contract 
>> >    based approach. 
>> >    An interface can only express the methods which a single type needs 
>> to 
>> >    satisfy and so a separate interface is needed for each mutually 
>> >    referential type parameter. A contract on the other hand doesn't 
>> have 
>> >    this constraint and, indeed, the type parameters as a group have to 
>> >    satisfy a single contract which, to my mind, ties the whole thing 
>> >    together in a much nicer way. 
>>
>> I actually have a fairly clear design in my head for adding associated 
>> types to interfaces, which my current design generalizes to cleanly, but 
>> I left it out because I'm not convinced that this kind of thing is 
>> common enough to be worth optimizing for. My gut is that this kind of 
>> contract will be the exception, rather than the rule, and I would err on 
>> the side of leaving things out. I think it will be common enough that 
>> we'll want it to be *doable*, but I'm not convinced being a little 
>> more concise is worth adding conceptual complexity. 
>>
>> >    3. Interfaces don't deal with fields at all and so would need to be 
>> >    extended to cope with a struct constraint. To be fair, some people 
>> have 
>> >    questioned whether such constraints are important enough to be 
>> catered 
>> >    for at all but the draft design does nevertheless deal with them and 
>> so 
>> >    does my own paper. 
>>
>> There's an issue on Github that Ian T ha referred to in several threads 
>> re: adding fields to interfaces, which has been rejected. I think 
>> the arguments against it all also apply to using contracts to do the 
>> same thing (see also my complaints about expressing intent) I'm not 
>> convinced that the fact that contracts can express this is a good thing. 
>>
>> >    4. There are a number of minor (though tricky) issues which 
>> interfaces 
>> >    can't currently deal with but contracts can and which I listed in my 
>> >    paper. To take one in particular - excluded types - it is difficult 
>> to 
>> >    see how interfaces could deal with something like that though, as 
>> it's 
>> >    a novel idea anyway, perhaps some other way could be found to 
>> achieve 
>> >    the same result. 
>>
>> Are there other use cases for this besides the numeric range issue? If 
>> not I think this falls into the same bucket as the add1k example, and I 
>> will have to think about it. 
>>
>> >    5. Finally - and you might think this is a bit silly - but there are 
>> a 
>> >    lot of people who don't like the idea of generics at all and will 
>> >    probably try to avoid them if they can. Now, hopefully they will 
>> change 
>> >    their minds when they see how convenient generics can be to use. 
>> >    Nevertheless, I still think it's important to cater for such people 
>> and 
>> >    leaving interfaces as they are and confining the generic stuff to 
>> >    contracts should help here. 
>>
>> My proposal doesn't really change interfaces themselves in any 
>> meaningful way -- it just applies them to bounding type parameters, 
>> mostly as-is. 
>>
>

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

Reply via email to