>
>  When is it important to not just express what operations are 
> required for a type, but also to try to rule out some types? 
>

I think the short answer is: numeric code. That's when one thinks about 
which types make sense for an algorithm, not just which operations.

I'm not exactly sure why. It could be because Go doesn't support operator 
overloading. In C++ with concepts, maybe the concept for writing some 
generic math function wants operator+ and operator/, and no one cares that 
that may result in nonsense for some implementations of those operators.

 In Go 1, we write numeric code with specific types: float64 and not int64, 
for instance. Go  insists on conversions between numeric types to keep us 
out of trouble: you can't call func Average(a, b float64) on ints without 
explicitly converting them. It seems natural to want to keep that precision 
and safety, but generalize it.

In Go 1, if we wanted to write a numeric algorithm that worked on, say, two 
slices of floating-point numbers, we'd give it the signature func(x, y 
[]float64). If later we wanted to support float32, we'd have to copy the 
code, or make the caller do an expensive conversion. The same problem would 
happen if the caller defined their own floating-point type (e.g. type 
MyFloat float64).

I think I should be able to say, simply and clearly, that the slice element 
can be any type whose underlying type is float32 or float64. Furthermore, I 
don't want to specify the exact operations my implementation currently 
uses. I may want to change the code to use "-" instead of "+" later, for 
reasons of clarity or numerical stability. I shouldn't have to update the 
contract for that.

contract(t T) { t = 0.0 } might seem to restrict to the types I want, but 
it doesn't; you can assign 0.0 to an integer type. 

contract(t T) { t = 0.5 } is wrong too. It includes complex types.

contract(t T) { float64(t) } also works for ints, so no good.

I believe the answer is 

   contract(t T) { t = 0.5; float64(t) }

but I'm not positive about that. Certainly, very few people who read that 
will immediately understand that T is a type whose underlying type is a 
float.

(And I haven't done the second part, where I add all the valid operators 
for floats.)

Earlier you wrote

> [T]o me it always seems quite clear which type arguments a contract 
allows 
and excludes.  It's exactly the set of types that type check 
successfully.  It's true that sometimes this can be a surprising type, 
but to me that seems just like the fact that it can be surprising 
which types implement an interface. 

I think this example, and the other ones given in this thread, demonstrate 
that this is not "just like" the surprise of which types implement an 
interface. It's more like solving a puzzle, as someone (Axel?) has said.

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