Bug 12408 – map does not like inout

Status
RESOLVED
Resolution
INVALID
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2014-03-18T18:20:59Z
Last change time
2021-03-19T17:45:45Z
Assigned to
No Owner
Creator
Infiltrator
See also
https://issues.dlang.org/show_bug.cgi?id=15651

Comments

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 :/