I’m kind of baffled that that even compiles because your sum_slice doesn’t include an Add constraint, which should be necessary for using +. But indeed it does. For demonstration, here’s a program that will fail to compile because T satisfies Zero but notAdd:
use std::num::Zero;
#[deriving(Show)]
struct MyNum(int);
impl Zero for MyNum {
fn zero() -> MyNum { MyNum(0) }
fn is_zero(&self) -> bool {
0 == { let MyNum(x) = *self; x }
}
}
fn sum_slice<T: Zero>(xs: &[T]) -> T {
let zero: T = Zero::zero();
xs.iter().fold(zero, |x, y| { x + *y })
}
fn main() {
let xs: Vec<MyNum> = vec![1, 2, 3].move_iter().map(MyNum).collect();
println!("{}", sum_slice(xs.as_slice()));
}
Which is what I’d expect. If you add an implementation for Add, then it compiles again!
Bah, ignore me. The doco for the Zero trait was somehow hiding the fact that it is already constrained with Add<Self, Self>. I didn’t see it until I looked at the source. Weird.
For those following at home, sum_slice already has a trait AdditiveIterator in std::iter. It seems the Add<A, A> constraint there is redundant since Zero is specified.
Indeed, I was as surprised as you to see I didn’t need the Add bound on T. Oddly enough, the Add<Self, Self> supertrait is shown in the docs for core::num::Zero but not std::num::Zero. Opened an issue here: https://github.com/mozilla/rust/issues/14636
generic add = {sl : @a::(numeric,integral)[:]
var x = 0 /* 0 is of type @t::(numeric,integral) */
for v in sl
x += v
;;
}
const main = {
const i8 : int8[:] = [1,2,3,4,5][:]
const i32 : int32[:] = [1,2,3,4,5][:]
sum(i8)
sum(i32)
}
This doesn’t pass dictionaries, though. It specializes fully at compile time. So, not quite equivalent. (I really need to figure out dynamic dispatch/late binding one of these days…)
In theory once you can extend protocols with methods you can get a lot closer to Haskell-like type classes. The type class instance gets replaced with self. Anything Monoid-like will have a .concat method, etc.
This is similar to extension methods on interfaces in C#. API discoverability is amazing once you have this. Imagine anything lens-like having all of the usable lens methods auto-complete after you type the dot. C# developers are already spoiled with this feature.
One of the developers said they’ve design Swift protocols with this in mind, so there’s some hope yet.
For comparison, the equivalent in Rust:
I think we can do better in 2014 than pass typeclass dictionaries around by hand.
I’m kind of baffled that that even compiles because your
sum_slicedoesn’t include anAddconstraint, which should be necessary for using+. But indeed it does. For demonstration, here’s a program that will fail to compile becauseTsatisfiesZerobut notAdd:Which is what I’d expect. If you add an implementation for
Add, then it compiles again!Freaky.
Bah, ignore me. The doco for the Zero trait was somehow hiding the fact that it is already constrained with
Add<Self, Self>. I didn’t see it until I looked at the source. Weird.For those following at home,
sum_slicealready has a trait AdditiveIterator instd::iter. It seems theAdd<A, A>constraint there is redundant sinceZerois specified.Indeed, I was as surprised as you to see I didn’t need the
Addbound onT. Oddly enough, theAdd<Self, Self>supertrait is shown in the docs forcore::num::Zerobut notstd::num::Zero. Opened an issue here: https://github.com/mozilla/rust/issues/14636I’m confused why
Numshould be a functor.. by all rights it should be a signature. The equivalent SML would beIn myrddin:
This doesn’t pass dictionaries, though. It specializes fully at compile time. So, not quite equivalent. (I really need to figure out dynamic dispatch/late binding one of these days…)
In theory once you can extend protocols with methods you can get a lot closer to Haskell-like type classes. The type class instance gets replaced with self. Anything Monoid-like will have a .concat method, etc.
This is similar to extension methods on interfaces in C#. API discoverability is amazing once you have this. Imagine anything lens-like having all of the usable lens methods auto-complete after you type the dot. C# developers are already spoiled with this feature.
One of the developers said they’ve design Swift protocols with this in mind, so there’s some hope yet.