On Thursday, 23 July 2015 at 19:55:30 UTC, Walter Bright wrote:
On 7/23/2015 8:03 AM, Dicebot wrote:
At the same time one HUGE deal breaker with rust traits that
rarely gets
mentioned is the fact that they are both constraints and
interfaces at the same
time:
// this is template constraint, it will generate new `foo`
symbol for each new T
fn foo <T : InputRange> (range : T)
// this use the very same trait definition but creates "fat
pointer" on demand
with simplistic dispatch table
fn foo (range : InputRange)
It kills all the necessity for hacks like RangeObject and is
quite a salvation
once you get to defining dynamic shared libraries with stable
ABI.
This is probably my most loved feature of Rust.
D interface types also produce the simplistic dispatch table,
and if you make them extern(C++) they don't need a RangeObject.
I know it isn't as convenient as what you describe above, but
it can be pressed into service.
I am not sure how it applies. My point was about the fact that
`isInputRange` and `InputRangeObject` are the same entities in
Rust, simply interpreted differently by compiler depending on
usage context.
This is important because you normally want to design your
application in terms of template constraints and structs to get
most out of inlining and optimization. However, to define stable
ABI for shared libraries, the very same interfaces need to be
wrapped in runtime polymorphism.
Closest thing in D would be to define traits as interfaces and
use code like this:
void foo(T)()
if ( (is(T == struct) || is(T == class))
&& Matches!(T, Interface)
)
{ }
where `Matches` is a template helper that statically iterates
method list of interface and looks for matching methods in T.
However, making it built-in feels really convenient in Rust:
- considerably less function declaration visual noise
- much better error messages: trying to use methods of T not
defined by a trait will result in compile-time error even without
instantiating the template