D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 12408 - map does not like inout
Summary: map does not like inout
Status: RESOLVED INVALID
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P2 normal
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-03-18 18:20 UTC by Infiltrator
Modified: 2021-03-19 17:45 UTC (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Infiltrator 2014-03-18 18:20:59 UTC
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 Infiltrator 2014-03-18 20:11:27 UTC
Possible duplicate of #8407?
Comment 2 monarchdodra 2014-03-19 16:06:56 UTC
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 Infiltrator 2014-03-19 21:42:25 UTC
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 monarchdodra 2014-03-20 02:02:14 UTC
(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 :/