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 [email protected].
For more options, visit https://groups.google.com/d/optout.