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

Reply via email to