As it's clear now that Ian wants to stick with 'full-blooded' contracts if 
it can be made to work, I've been trying to think of ways to make them 
easier to work with and to solve some of the issues they currently have.

Reading through the draft for the umpteenth time, one point that 
particularly struck me was that expressions such as:

1. ' t == t  ' implies that both == and != are valid operations i.e. type 
is comparable.

2  ' t * t  ' implies both * and *= are valid.

3. ' t < t  ' implies that <, >, <=, >= , == and != are all valid i.e. type 
is ordered.

Suppose this idea were taken to its logical conclusion.

So in the case of #2 the compiler could further imply that it must be 
dealing with an integer, floating point or complex type (as only those 
types support the multiplication operator) and that consequently ALL the 
operations, conversions, assignments etc. which those types had in common 
could be used by a generic function/type that was constrained by a contract 
containing that expression.

Similarly, #3 would tell the compiler that it must be dealing with an 
integer, floating point or string type as only those types are ordered.

It's easy to think of a number of other simple expressions where the 
compiler could imply the allowable types:

4. ' t % t  ' implies any integer type.

5. ' 1 << t ' implies an unsigned integer type.

6. ' -1 ^ t ' implies a signed integer type.

7. ' t == 1.1 ' implies a floating point or complex type.

8. ' imag(t) ' implies a complex type.

9. ' !a ' implies a boolean type.

10. ' t  == "" ' implies a string type.

11. ' []byte(a) ' implies a string type or byte slice.

12. ' []rune(a) ' implies a string type or rune slice.

13. ' a + a ' implies an integer, floating point, complex or string type.

Now let's further suppose that the standard library contained a contracts 
package (with a nice short name such as 'ct') containing contracts for each 
of these expressions. Let's give them some shortish names such as (in the 
same order):
 
   Eq, Num, Ord, Int, Uns, Sgnd, Float, Cmplx, Bool, Str, Bytes, Runes, Add 

So, for the first one, the actual code would be:

contract Eq(t T) {
    t == t
}

Of course, as the code is not going to be executed, all that matters is 
that these expressions survive the type checker for the actual type used.

The advantage of doing something like this is that where you only need a 
single type parameter and are happy to constrain it to one of these 
'type-classes', you could do so straight 'out of the box' with a contract 
such as ct.Int, ct.Str or whatever. I suspect that this would cover a large 
percentage of use cases in practice and so would be a worthwhile feature.

It might also satisfy those of us who favored a 'type-class' based 
solution, particularly as it doesn't require any more built-ins or other 
syntactic overhead compared to the original proposal.

It's giving the compiler more to do in one way but less to do in another as 
it should solve nearly all operator/conversion problems without further 
ado. It should also solve the problems we currently have with untyped 
constants.

For more complicated cases, the full power of user defined contracts would 
still be available.

Does anyone else think there's any mileage in this idea or am I just 
whistling in the dark?
  
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.
For more options, visit https://groups.google.com/d/optout.

Reply via email to