Rant after trying Rust a bit

Artur Skawina via Digitalmars-d digitalmars-d at puremagic.com
Fri Jul 24 13:57:19 PDT 2015


On 07/24/15 20:29, Walter Bright via Digitalmars-d wrote:
> On 7/24/2015 4:55 AM, Artur Skawina via Digitalmars-d wrote:
>> 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)
> 
> That really isn't any different from a user calling it with a 'hasPrefix' that doesn't have a 'suffix'.

The difference is that right now the developer has to write a unit-test
per function that uses `hasPrefix`, otherwise the code might not even be
verified to compile. 100% unit-test coverage is not going to happen in
practice, and just like with docs, making things easier and reducing
boilerplate to a minimum would improve the situation dramatically.


>> - 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.
> 
> As I mentioned in the antecedent, this pulls the teeth of the point of the trait, because what the function needs is 'hasPrefix && hasSuffix', and your position is that only 'hasPrefix' is required.

The function only needs what it uses, ie the i/f defined by `hasPrefix`.
It can optionally access other i/fs like `hasSuffix` if the type supports
them, and it can do so w/o affecting callers (or callees).
Iff you modify the function to /require/ both traits, then, yes, you need
to also update the traits, eg create and use a `hasAdfixes` trait instead.
This is a feature and not a problem; traits would of course be opt-in and
using them only makes sense when the interfaces are very stable, like
D's ranges -- if a required primitive is added, removed or modified then
the range-traits *should* be updated.


> This leaves us exactly where D is now.

No, right now D does not provide any (built-in) functionality for
restricting (and automatically documenting) non-dynamic interfaces.


>> [1] "and more": it allows for overloading on traits, something
>>      that can not be (cleanly) done with constraints.
> 
> Overloading with constraints is commonplace in Phobos. Haven't really had any trouble with it.

It doesn't work (ie does not scale) when the constraints are non-
exclusive. At some point one reaches for:

   template _pick_f(T) {
      static if (is(T:ForwardRange)/*&&smth&&(!smth_else||wever)*/)
         enum _pick_f = 1;
      else static if (is(T:ForwardRange)/*&&!(smth&&(!smth_else||wever))*/)
         enum _pick_f = 2;
      else static if (is(T:InputRange))
         enum _pick_f = 3;
      /*...*/
   }
   auto f(T)(T a) if (_pick_f!T==1) {/*...*/}
   auto f(T)(T a) if (_pick_f!T==2) {/*...*/}
   auto f(T)(T a) if (_pick_f!T==3) {/*...*/}

Ugly as it is, it's still better than the alternative (where the
ugliness isn't contained, but spread out over all `f` definitions
and not guaranteed to be coherent).

artur


More information about the Digitalmars-d mailing list