Comment #0 by ali.akhtarzada — 2019-03-18T10:38:32Z
Using inout with type constructors causes the wrong type to be inferred.
struct S(T) {
T value = T.init;
}
auto ref make(T)(inout auto ref T value) {
// T == char[] when infact it's string
return inout(S!T)(value);
}
auto ref f(T)(inout auto ref S!T s) {
return make(s.value);
}
auto a = [make("hello"), S!string("hello")];
Probably related to 19126.
Comment #1 by ali.akhtarzada — 2019-03-18T10:39:16Z
Forgot this: it causes "Error: incompatible types for (make("hello")) : (S("hello")): immutable(S!(char[])) and S!string"
Comment #2 by dfj1esp02 — 2019-03-18T12:36:41Z
Well, that's how inout works.
Simple inference does what you want:
struct S(T) {
T value;
}
auto make(T)(ref T value) {
return S!T(value);
}
auto f(T)(ref T s) {
return make(s.value);
}
void f() {
class C {}
C c;
auto s1 = S!C(c);
const s2 = make!C(c);
auto s3 = f(s2);
}
Comment #3 by ali.akhtarzada — 2019-03-18T13:51:05Z
What do you mean that's how inout works? It works by changing your types? Why is it secretly changing my types?
And try adding a function that takes an S!T instead of a catch all and simple inference doesn't work anymore. It's not scalable to have opaque types on every function:
auto f(T)(auto ref S!T s) {
return make(s);
}
Also, if inout changes the type that you expect then even more insanity ensues:
struct S(T) {
static if (is(T == char[])) {
// implement 1
} else {
// implement 2
}
}
auto a = make("hi"); // implementation 1
auto b = S!string("hi") // implementation 2
Comment #4 by dfj1esp02 — 2019-03-18T16:16:51Z
inout is a wildcard for const qualifiers, so instead of mutable, const and immutable you see inout. Inference provides you the qualifiers unchanged. To restrict types you can use static assert or template constraints.
Comment #5 by ali.akhtarzada — 2019-03-21T08:52:05Z
No it doesn't. It changes them by moving them around.
struct S(T) {
pragma(msg, T);
}
auto make(T)(inout T s) { return inout S!T(); }
pragma(msg, typeof(make("hi")));
// prints
// char[]
// immutable(S!(char[]))
Comment #6 by dfj1esp02 — 2019-03-21T15:48:30Z
If you want to preserve types, use inference:
struct S(T) {
pragma(msg, T);
}
auto make(T)(T s) { return S!T(); }
pragma(msg, typeof(make("hi")));
prints
---
string
S!string
---
Comment #7 by ali.akhtarzada — 2019-03-21T23:58:46Z
That can't be used by other inout functions.
The whole point of inout is to be able to handle const/immutable/mutable without having to write 3 variations of a function.
Comment #8 by dfj1esp02 — 2019-03-22T09:12:39Z
But then you can't preserve qualifiers, because the results must be identical. If you want to preserve qualifiers, you need 3 different templates.
Comment #9 by dfj1esp02 — 2019-03-22T09:15:14Z
S!(char[])
S!(const char[])
S!string
Can't be the same template, they are different types with distinct code generated for each of them. So they can't be handled by the same code.
Comment #10 by ali.akhtarzada — 2019-03-22T10:21:37Z
(In reply to anonymous4 from comment #9)
> S!(char[])
> S!(const char[])
> S!string
> Can't be the same template, they are different types with distinct code
> generated for each of them. So they can't be handled by the same code.
Exactly. And inout is generating the wrong one!
Anyway, it seems I've filed this before -> https://issues.dlang.org/show_bug.cgi?id=19125
Comment #11 by ali.akhtarzada — 2019-07-18T10:24:29Z
*** This issue has been marked as a duplicate of issue 19125 ***