On 07/24/15 06:43, Walter Bright via Digitalmars-d wrote: > On 7/23/2015 3:12 PM, Dicebot wrote: >> On Thursday, 23 July 2015 at 22:10:11 UTC, H. S. Teoh wrote: >>> OK, I jumped into the middle of this discussion so probably I'm speaking totally out of context... >> >> This is exactly one major advantage of Rust traits I have been trying to explain, thanks for putting it up in much more understandable way :) > > Consider the following: > > int foo(T: hasPrefix)(T t) { > t.prefix(); // ok > bar(t); // error, hasColor was not specified for T The fact that some other concept/trait implementations got it wrong is not really an argument against a sane implementation. Basically, it can work like this: - traits, like your 'hasPrefix', check that 'T' implements an interface (defined in hasPrefix). (this does the job that template constraints do right now, and more [1]) - the compiler instantiates the template with a mock (defined inside 'hasPrefix'). (this immediately catches every illegal access, like 't.suffix' and results in a clear and informative error message) - the 'T' inside foo is still the original type that it was called with, so 'bar(t)' will succeed. But it needs to be conditionally enabled for just the types that implement 'hasColor' -- and this is exactly what you'd want from traits. So guard it, for example, `static if (is(T:hasColor)) bar(t);`; note that when 'bar(t)` is an alias or mixin, this can be done inside the aliased or mixed-in code. There are some syntax sugar possibilities here (aot there should be a way to access other traits without introducing a named function). http:// forum. dlang.org/ post/ mailman.4484. 1434139778. 7663. digitalmars- d@purem agic.com has one example, using a slightly different syntax (the 'idiomatic D' way would be an is-expression inside static-if introducing the alias, but `is()` makes code extremely ugly and unreadable). [1] "and more": it allows for overloading on traits, something that can not be (cleanly) done with constraints. When there is more than one candidate template, the compiler can easily determine the most specialized one, eg if both 'InputRange' and 'ForwardRange' matches, it just needs to try to instantiate IR with the mock from FW range trait (and vice versa); if that fails then it means that FW should be chosen. IOW it works similarly to "normal" template overload resolution. Note that this only needs to be done (lazily/on-demand) once per trait-set. > } > > void bar(T: hasColor)(T t) { > t.color(); > } > > Now consider a deeply nested chain of function calls like this. At the bottom, one adds a call to 'color', and now every function in the chain has to add 'hasColor' even though it has nothing to do with the logic in that function. No, as long as the extra functionality is optional no changes to callers are required, at least not for statically dispatched code that we're talking about here. If the new code /requires/ extra functionality then it needs to be explicitly requested. This is no different from how D classes work -- you either have to request a subclass to use it, or check with `cast(SubClass)` at run-time. Traits work at compile-time, that's all. artur