Comment #0 by lt.infiltrator — 2014-03-18T18:20:59Z
http://dpaste.dzfl.pl/cd03223f4472
----------------------------------------------------
import std.algorithm : map;
class L {
auto fun(const S s) inout nothrow pure @safe {
if(point[0] is s)
return point[1];
else
return point[0];
}
this(S a, S b) {
point = [a, b];
}
S[2] point;
}
class S {
@property auto foo() inout nothrow pure @safe {
return arr.map!(e => e.fun(this));
}
L[] arr;
}
void main() { }
----------------------------------------------------
Fails to compile:
/opt/compilers/dmd2/include/std/algorithm.d(438): Error: variable f922.S.foo.MapResult!(__lambda1, inout(L)[]).MapResult._input only parameters or stack based variables can be inout /opt/compilers/dmd2/include/std/algorithm.d(390): Error: template instance f922.S.foo.MapResult!(__lambda1, inout(L)[]) error instantiating /d556/f922.d(18): instantiated from here: map!(inout(L)[]) /d556/f922.d(18): Error: template instance f922.S.foo.map!((e) => e.fun(this)).map!(inout(L)[]) error instantiating /d556/f922.d(18): Error: template std.algorithm.map cannot deduce function from argument types !((e) => e.fun(this))(inout(L[])), candidates are: /opt/compilers/dmd2/include/std/algorithm.d(375): std.algorithm.map(fun...) if (fun.length >= 1)
Comment #1 by lt.infiltrator — 2014-03-18T20:11:27Z
Possible duplicate of #8407?
Comment #2 by monarchdodra — 2014-03-19T16:06:56Z
Seems invalid to me. Take a look at this reduced example:
//----
struct L(T)
{
T t;
}
auto l(T)(T t)
{
return L!T();
}
class S
{
auto foo() inout
{
return l(a);
}
int a;
}
void main() { }
//----
What's basically happening in "foo", is you are creating a type `L!(inout(int))`, which has a member t with qualifier `inout(int)`. That don't make no sense.
You need to chose the static type you are returning. The type *itself* may be marked as inout. However, that's not what you are doing: You are returning a type that's parameterized on inout, which is not the same at all.
The idea of "inout" (as I have understood it), is that there is a *single* implementation that is compatible for all of const/immutable/mutable. That's not quite what you are doing. I think you simply need a const/non-const overload. Then, they'll return 2 actual different types "map!(L[])" and "map!(const(L)[])" (and you can even add an immutable overload if you so wish).
Comment #3 by lt.infiltrator — 2014-03-19T21:42:25Z
I thought that the whole point of using inout was to avoid having to copy-paste code between mutable, const, and immutable functions? As you've described (unless I'm misunderstanding), I should copy-paste
@property auto foo() inout nothrow pure @safe {
return arr.map!(e => e.fun(this));
}
as mutable, const, and nothrow. Shouldn't this be something which should be fixed with inout and/or templates themselves?
Comment #4 by monarchdodra — 2014-03-20T02:02:14Z
(In reply to comment #3)
> I thought that the whole point of using inout was to avoid having to
> copy-paste code between mutable, const, and immutable functions?
Yes, that's it's design, but it's not magic either. It makes it so that a single *implementation* can work as mutable or immutable.
What you are asking for is actually 3 different implementations (3 different return types).
At least, that's how I understood the issue. Maybe bring it up on learn to see if I'm wrong.
That said, please think about your design, and what it means to have const/non-const overloads that return different types.
> As you've described
> (unless I'm misunderstanding), I should copy-paste
>
> @property auto foo() inout nothrow pure @safe {
> return arr.map!(e => e.fun(this));
> }
>
> as mutable, const, and nothrow. Shouldn't this be something which should be
> fixed with inout and/or templates themselves?
Maybe there is a template solution, but (AFAIK) templates don't have the capability of conditionally tagging things as const or not.
I'd have thought mixin templates could solve this, like this:
//----
mixin template fooImpl()
{
auto foo()
{
return l(a);
}
}
mixin fooImpl!();
const mixin fooImpl!();
immutable mixin fooImpl!();
//----
But apparently, the qualifiers are ignored, and this simply creates the same function 3 times.
So I don't see anything other than string mixins :/