"2. Generics (both types and immutable constraints), I think C++1z has the right approach to this (and constexpr and constant arrays are nice and are able to provide more hints to the compiler)."
---
think about the code examples in these subsections:
http://cglab.ca/~abeinges/blah/rust-reuse-and-recycle/#generics
http://cglab.ca/~abeinges/blah/rust-reuse-and-recycle/#aside-generic-inference-and-the-turbofish ---
also, in http://cglab.ca/~abeinges/blah/rust-reuse-and-recycle/#generics , i don't quite understand why need need two <T>s in the following declaration:
// Implementing functionality for all choices of T.
// Note that the "impl" is also Generic here.
// Hopefully this in conjunction with the previous
// example demonstrates why the extra <T> is necessary.
impl<T> Generic<T> {
fn new(data: T) -> Generic<T> {
Generic { data: data }
}
fn get(&self) -> &T {
&self.data
}
}
My guess based on other examples with <> after 'impl' later on that same webpage is that the first <T>, impl<T>, is just saying that the following declaration will have a type variable in it ('T'). Which i don't see why we really need, because we can infer it from the presence of capital T inside Generic<T>, right? But i guess this is like how we want to have 'lambda x: x + 2' not just 'x + 2' and let the compiler find out that 'x' hasn't been previously defined; also, in some examples further down that webpage, there is stuff like:
impl<T: Clone> Clone for Generic<T> { fn clone(&self) -> Self { Generic { data: self.data.clone() } } }
where there is a 'trait bound' on 'T' (why don't they call it a 'type bound'?) that says that T must implement trait 'Clone'.
i wonder if this stuff could be simplified by using ordinary function notation here, something like:
Clone for Generic<T> := fn(T :: Clone) {...}
(obviously this isn't quite right, but you see where i'm going; you are explicitly representing that T is a parameter using ordinary function notation)
---
if we have 'type attribute', need a syntax to say, within a type annotation "x has type attribute A, AND x also has type attribute B". Eg if you want to say that type "T" implements interface 'Box', and also "T" implements interface 'Clone', would you say:
T <: Box && T <: Clone
?
also, should we reserve '<:' for subtypes and have some other syntax for 'implements'?
also, interestingly, these are logical assertions, not imperative computations.
is this sort of notation what you'd find in the arguments of a function-style syntax for type bounds in genericity, as in the previous section? eg
... := fn(T :: T <: Box && T <: Clone)
that doesn't look quite right, because you expect to see stuff like
x :: int16
meaning "x ISA instance of type int16", but "T :: T <: Box && T <: Clone" up there means "T SUCH-THAT T is a subtype of Box and T is a subtype of Clone"
why not just have
T :: Box && Clone
to mean '(T s.t. T IS Box) AND (T s.t. T IS Clone)' where IS combines ISA and isSubtype as noted previously? That seems a little ambiguous, though.
hmm.
---
in Haskell, one reason for the "monomorphism restriction", according to [1], is to prevent surprising repetition of computation; eg without the monomorphism restriction, in
genericLength :: Num a => [b] -> a
let { len = genericLength xs } in (len, len)
each 'len' in '(len, len)' will be computed separately, so 'genericLength xs' will be evaluated twice. In [2], CaleGibbard? explains "The trouble is that typeclasses essentially introduce additional function parameters -- specifically, the dictionary of code implementing the instances in question. In the case of typeclass polymorphic pattern bindings, you end up turning something that looked like a pattern binding -- a constant that would only ever be evaluated once, into what is really a function binding, something which will not be memoised.".
So i guess CaleGibbard?