Rant after trying Rust a bit

Artur Skawina via Digitalmars-d digitalmars-d at puremagic.com
Fri Jul 24 04:55:06 PDT 2015


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@puremagic.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


More information about the Digitalmars-d mailing list