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